From 59f43d6e06a15eced3ae28386f0b3b5ea9d35f89 Mon Sep 17 00:00:00 2001 From: kuenking Date: Tue, 22 Dec 2020 15:58:00 +0800 Subject: [PATCH 1/7] I2ACPU: add appcds file lock --- add-appcds-file-lock.patch | 461 +++++++++++++++++++++++++++++++++++++ java-1.8.0-openjdk.spec | 7 +- 2 files changed, 467 insertions(+), 1 deletion(-) create mode 100755 add-appcds-file-lock.patch diff --git a/add-appcds-file-lock.patch b/add-appcds-file-lock.patch new file mode 100755 index 0000000..b338d12 --- /dev/null +++ b/add-appcds-file-lock.patch @@ -0,0 +1,461 @@ +diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp +index f27d04d0..306315e9 100644 +--- a/hotspot/src/share/vm/classfile/classFileParser.cpp ++++ b/hotspot/src/share/vm/classfile/classFileParser.cpp +@@ -4022,8 +4022,12 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, + if (_host_klass == NULL && SystemDictionaryShared::is_sharing_possible(loader_data)) { + if (name != NULL) { + ResourceMark rm(THREAD); +- classlist_file->print_cr("%s", name->as_C_string()); +- classlist_file->flush(); ++ char *class_name = name->as_C_string(); ++ // TODO Skip JFR-related classes in classlist file to avoid conflicts between appcds and jfr. ++ if ((class_name != NULL) && (strstr(class_name, "jfr") == NULL)) { ++ classlist_file->print_cr("%s", class_name); ++ classlist_file->flush(); ++ } + } + } + } +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp +index d27bf484..3f28d38e 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp +@@ -1283,41 +1283,43 @@ instanceKlassHandle SystemDictionary::load_shared_class( + // null) or the same class loader is used to load previously + // defined class + bool bFound = false; +- if (class_loader.is_null()) { +- // condition1: Bootstrap class loader loaded +- bFound = (ik()->class_loader_data() == NULL || ik()->class_loader_data()->is_the_null_class_loader_data()); +- } else if (ik()->class_loader_data() != NULL) { +- // condition2: App Class Loader +- // condition3: ExtClass Loader +- // Condition4: not fake class Loader, real one +- bFound = ((ik->has_fake_loader_data_App() && SystemDictionary::is_app_class_loader(class_loader)) || +- (ik->has_fake_loader_data_Ext() && SystemDictionary::is_ext_class_loader(class_loader)) || +- (!ik->has_fake_loader_data() && ik()->class_loader() == class_loader())); +- } +- if (!bFound) { +- return instanceKlassHandle(); +- } ++ if (class_loader.is_null()) { ++ // condition1: Bootstrap class loader loaded ++ bFound = (ik()->class_loader_data() == NULL || ik()->class_loader_data()->is_the_null_class_loader_data()); ++ } else if (ik()->class_loader_data() != NULL) { ++ // condition2: App Class Loader ++ // condition3: ExtClass Loader ++ // condition4: not fake class Loader, real one ++ bFound = ((ik->has_fake_loader_data_App() && SystemDictionary::is_app_class_loader(class_loader)) || ++ (ik->has_fake_loader_data_Ext() && SystemDictionary::is_ext_class_loader(class_loader)) || ++ (!ik->has_fake_loader_data() && ik()->class_loader() == class_loader())); ++ } ++ if (!bFound) { ++ return instanceKlassHandle(); ++ } + +- // get protection domain for this class if not loaded by null class loader +- if (class_loader.not_null()) { +- ResourceMark rm(THREAD); +- char* name = ik->name()->as_C_string(); +- Handle klass_name = java_lang_String::create_from_str(name, CHECK_0); +- JavaValue result(T_OBJECT); +- +- // ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); +- JavaCalls::call_virtual(&result, +- class_loader, +- KlassHandle(THREAD, SystemDictionary::URLClassLoader_klass()), +- vmSymbols::getProtectionDomainInternal_name(), +- vmSymbols::getProtectionDomainInternal_signature(), +- klass_name, +- THREAD); +- return load_shared_class(ik, class_loader, Handle(THREAD, (oop) result.get_jobject()), THREAD); +- } else { +- return load_shared_class(ik, class_loader, Handle(), THREAD); +- } ++ // get protection domain for this class if not loaded by null class loader ++ if (class_loader.not_null()) { ++ ResourceMark rm(THREAD); ++ char* name = ik->name()->as_C_string(); ++ Handle klass_name = java_lang_String::create_from_str(name, CHECK_0); ++ JavaValue result(T_OBJECT); ++ ++ // load_shared_class need protected domain to handle non-bootstrap loaded class, ++ // so here call_virtual to call getProtectionDomainInternal function of URLClassLoader.java, ++ // to get protected domain and save into result. ++ JavaCalls::call_virtual(&result, ++ class_loader, ++ KlassHandle(THREAD, SystemDictionary::URLClassLoader_klass()), ++ vmSymbols::getProtectionDomainInternal_name(), ++ vmSymbols::getProtectionDomainInternal_signature(), ++ klass_name, ++ THREAD); ++ return load_shared_class(ik, class_loader, Handle(THREAD, (oop) result.get_jobject()), THREAD); ++ } else { ++ return load_shared_class(ik, class_loader, Handle(), THREAD); + } ++ } + } + return instanceKlassHandle(); + } +@@ -1396,8 +1398,12 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, + // unless AppCDS is enabled + if (SystemDictionaryShared::is_sharing_possible(loader_data)) { + ResourceMark rm(THREAD); +- classlist_file->print_cr("%s", ik->name()->as_C_string()); +- classlist_file->flush(); ++ char *class_name = ik->name()->as_C_string(); ++ // TODO Skip JFR-related classes in classlist file to avoid conflicts between appcds and jfr. ++ if ((class_name != NULL) && (strstr(class_name, "jfr") == NULL)) { ++ classlist_file->print_cr("%s", class_name); ++ classlist_file->flush(); ++ } + } + } + +@@ -1472,8 +1478,10 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha + // the call stack. Bootstrap classloader is parallel-capable, + // so no concurrency issues are expected. + CLEAR_PENDING_EXCEPTION; +- k = JfrUpcalls::load_event_handler_proxy_class(THREAD); +- assert(!k.is_null(), "invariant"); ++ if (!DumpSharedSpaces) { ++ k = JfrUpcalls::load_event_handler_proxy_class(THREAD); ++ assert(!k.is_null(), "invariant"); ++ } + } + #endif + +diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +index a8dbda2e..1bd61b02 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp ++++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +@@ -28,6 +28,7 @@ + + #include "classfile/dictionary.hpp" + #include "classfile/systemDictionary.hpp" ++#include "verifier.hpp" + + class SystemDictionaryShared: public SystemDictionary { + public: +@@ -70,7 +71,16 @@ public: + static void finalize_verification_dependencies() {} + static bool check_verification_dependencies(Klass* k, Handle class_loader, + Handle protection_domain, +- char** message_buffer, TRAPS) {return true;} ++ char** message_buffer, TRAPS) { ++ if (EnableSplitVerifierForAppCDS) { ++ ClassVerifier split_verifier(k, THREAD); ++ split_verifier.verify_class(THREAD); ++ if (HAS_PENDING_EXCEPTION) { ++ return false; // use the existing exception ++ } ++ } ++ return true; ++ } + }; + + #endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP +diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp +index 9923058b..eb267b83 100644 +--- a/hotspot/src/share/vm/classfile/verifier.cpp ++++ b/hotspot/src/share/vm/classfile/verifier.cpp +@@ -561,7 +561,8 @@ void ClassVerifier::verify_class(TRAPS) { + + for (int index = 0; index < num_methods; index++) { + // Check for recursive re-verification before each method. +- if (was_recursively_verified()) return; ++ // in CDS Sharing state we still verify the code. ++ if (!UseAppCDS && was_recursively_verified()) return; + + Method* m = methods->at(index); + if (m->is_native() || m->is_abstract() || m->is_overpass()) { +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index 17447587..d2095e63 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -22,6 +22,7 @@ + * + */ + ++#include "jvm.h" + #include "precompiled.hpp" + #include "classfile/classLoader.hpp" + #include "classfile/sharedClassUtil.hpp" +@@ -33,10 +34,13 @@ + #include "memory/oopFactory.hpp" + #include "oops/objArrayOop.hpp" + #include "runtime/arguments.hpp" ++#include "runtime/globals.hpp" + #include "runtime/java.hpp" + #include "runtime/os.hpp" + #include "services/memTracker.hpp" ++#include "utilities/debug.hpp" + #include "utilities/defaultStream.hpp" ++#include "utilities/ostream.hpp" + + # include + # include +@@ -362,11 +366,33 @@ bool FileMapInfo::open_for_read() { + return true; + } + +- + // Write the FileMapInfo information to the file. +- + void FileMapInfo::open_for_write() { +- _full_path = make_log_name(Arguments::GetSharedArchivePath(), NULL); ++ if (UseAppCDS && AppCDSLockFile != NULL) { ++ char* pos = strrchr(const_cast(AppCDSLockFile), '/'); ++ if (pos != NULL && pos != AppCDSLockFile) { // No directory path specified ++ char buf[PATH_MAX + 1] = "\0"; ++ char filePath[PATH_MAX] = "\0"; ++ int length = pos - AppCDSLockFile + 1; ++ strncpy(filePath, AppCDSLockFile, length); ++ if (realpath(filePath, buf) == NULL) { ++ fail_stop("A risky filePath:%s, buf:%s, length:%d", filePath, buf, length); ++ } ++ _appcds_file_lock_path = os::strdup(AppCDSLockFile, mtInternal); ++ if (_appcds_file_lock_path == NULL) { ++ fail_stop("Failed to create appcds file lock."); ++ } ++ int lock_fd = open(_appcds_file_lock_path, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR); ++ if (lock_fd < 0) { ++ tty->print_cr("The lock path is: %s", _appcds_file_lock_path); ++ tty->print_cr("Failed to create jsa file !\n Please check: \n 1. The directory exists.\n " ++ "2. You have the permission.\n 3. Make sure no other process using the same lock file.\n"); ++ JVM_Exit(0); ++ } ++ tty->print_cr("You are using file lock %s in concurrent mode", AppCDSLockFile); ++ } ++ } ++ _full_path = make_log_name(Arguments::GetSharedArchivePath(), NULL); + if (PrintSharedSpaces) { + tty->print_cr("Dumping shared data to file: "); + tty->print_cr(" %s", _full_path); +@@ -452,6 +478,7 @@ void FileMapInfo::write_bytes(const void* buffer, int nbytes) { + // close and remove the file. See bug 6372906. + close(); + remove(_full_path); ++ remove(_appcds_file_lock_path); + fail_stop("Unable to write to shared archive file.", NULL); + } + } +@@ -492,6 +519,10 @@ void FileMapInfo::write_bytes_aligned(const void* buffer, int nbytes) { + // Close the shared archive file. This does NOT unmap mapped regions. + + void FileMapInfo::close() { ++ if (UseAppCDS && AppCDSLockFile != NULL) { ++ // delete appcds.lock ++ remove(_appcds_file_lock_path); ++ } + if (_file_open) { + if (::close(_fd) < 0) { + fail_stop("Unable to close the shared archive file."); +diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp +index acff6c9d..c09fbca1 100644 +--- a/hotspot/src/share/vm/memory/filemap.hpp ++++ b/hotspot/src/share/vm/memory/filemap.hpp +@@ -143,6 +143,7 @@ public: + FileMapHeader * _header; + + const char* _full_path; ++ const char* _appcds_file_lock_path; + char* _paths_misc_info; + + static FileMapInfo* _current_info; +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index 073c38ac..ebb5e114 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -36,6 +36,7 @@ + #include "prims/jvmtiExport.hpp" + #include "runtime/arguments.hpp" + #include "runtime/arguments_ext.hpp" ++#include "runtime/globals.hpp" + #include "runtime/globals_extension.hpp" + #include "runtime/java.hpp" + #include "services/management.hpp" +@@ -1493,7 +1494,6 @@ void Arguments::set_use_compressed_oops() { + // the only value that can override MaxHeapSize if we are + // to use UseCompressedOops is InitialHeapSize. + size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize); +- + if (max_heap_size <= max_heap_for_compressed_oops()) { + #if !defined(COMPILER1) || defined(TIERED) + if (FLAG_IS_DEFAULT(UseCompressedOops)) { +@@ -3023,9 +3023,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, + if (!process_argument("+UseAppCDS", args->ignoreUnrecognized, origin)) { + return JNI_EINVAL; + } else { +- const char* n = "SharedArchiveFile"; +- Flag* shared_archive_flag = Flag::find_flag(n, strlen(n), true, true); +- shared_archive_flag->unlock_diagnostic(); + FLAG_SET_CMDLINE(bool, UseAppCDS, true); + } + } +@@ -3382,6 +3379,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, + } else if (match_option(option, "-Xshare:off", &tail)) { + FLAG_SET_CMDLINE(bool, UseSharedSpaces, false); + FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false); ++ // -Xtypecheck ++ } else if (match_option(option, "-Xtypecheck:on", &tail)) { ++ FLAG_SET_CMDLINE(bool, EnableSplitVerifierForAppCDS, true); + // -Xverify + } else if (match_option(option, "-Xverify", &tail)) { + if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) { +@@ -3632,7 +3632,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, + FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true); + FLAG_SET_CMDLINE(bool, TraceClassPaths, true); + } +- ++ if (DumpSharedSpaces && !UseAppCDS && AppCDSLockFile != NULL) { ++ jio_fprintf(defaultStream::error_stream(), "AppCDSLockFile is only used when AppCDS is enabled."); ++ return JNI_ERR; ++ } + // Change the default value for flags which have different default values + // when working with older JDKs. + #ifdef LINUX +@@ -4057,6 +4060,7 @@ static char* get_shared_archive_path() { + return shared_archive_path; + } + ++ + #ifndef PRODUCT + // Determine whether LogVMOutput should be implicitly turned on. + static bool use_vm_log() { +@@ -4199,6 +4203,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { + return JNI_ENOMEM; + } + ++ + // Set up VerifySharedSpaces + if (FLAG_IS_DEFAULT(VerifySharedSpaces) && SharedArchiveFile != NULL) { + VerifySharedSpaces = true; +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index 6f7ff138..03f293e3 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -473,6 +473,7 @@ class Arguments : AllStatic { + static bool CheckCompileOnly; + + static char* SharedArchivePath; ++ static char* AppCDSLockPath; + + public: + // Parses the arguments, first phase +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 65b11caa..b72efd45 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -4007,15 +4007,21 @@ class CommandLineFlags { + product(ccstr, SharedClassListFile, NULL, \ + "Override the default CDS class list") \ + \ +- diagnostic(ccstr, SharedArchiveFile, NULL, \ ++ product(ccstr, SharedArchiveFile, NULL, \ + "Override the default location of the CDS archive file") \ + \ ++ product(ccstr, AppCDSLockFile, NULL, \ ++ "Override the default location of the AppCDS lock file") \ ++ \ + product(ccstr, ExtraSharedClassListFile, NULL, \ + "Extra classlist for building the CDS archive file") \ + \ + product(bool, UseAppCDS, false, \ + "Enable Application Class Data Sharing (AppCDS)") \ + \ ++ product(bool, EnableSplitVerifierForAppCDS, false, \ ++ "Enable Type Check (AppCDS)") \ ++ \ + experimental(uintx, ArrayAllocatorMallocLimit, \ + SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \ + "Allocation less than this value will be allocated " \ +diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp +index 2b458fe4..587b839b 100644 +--- a/hotspot/src/share/vm/utilities/ostream.cpp ++++ b/hotspot/src/share/vm/utilities/ostream.cpp +@@ -34,6 +34,9 @@ + #include "utilities/ostream.hpp" + #include "utilities/top.hpp" + #include "utilities/xmlstream.hpp" ++ ++# include ++ + #ifdef TARGET_OS_FAMILY_linux + # include "os_linux.inline.hpp" + #endif +@@ -376,7 +379,7 @@ stringStream::~stringStream() {} + xmlStream* xtty; + outputStream* tty; + outputStream* gclog_or_tty; +-CDS_ONLY(fileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive ++CDS_ONLY(jsaFileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive + extern Mutex* tty_lock; + + #define EXTRACHARLEN 32 +@@ -760,6 +763,36 @@ void fileStream::flush() { + fflush(_file); + } + ++jsaFileStream::jsaFileStream(const char* file_name) : fileStream(file_name, "a") { ++ if (_file != NULL) { ++ if (flock(fileno(_file), LOCK_EX | LOCK_NB) != 0) { ++ if (errno == EWOULDBLOCK) { ++ warning("file %s is locked by another process\n", file_name); ++ } else { ++ warning("Cannot lock file %s due to %s\n", file_name, strerror(errno)); ++ } ++ fclose(_file); ++ _file = NULL; ++ _need_close = false; ++ } else { ++ if (::ftruncate(fileno(_file), 0) != 0) { ++ warning("Fail to ftruncate file %s due to %s\n", file_name, strerror(errno)); ++ } ++ ::rewind(_file); ++ } ++ } ++} ++ ++jsaFileStream::~jsaFileStream() { ++ // flock is released automatically when _file is closed ++ // Ensure the following sequnce in fclose ++ // 1. fflush. 2. flock(unlock); 3. close ++ if (_file != NULL) { ++ if (_need_close) fclose(_file); ++ _file = NULL; ++ } ++} ++ + fdStream::fdStream(const char* file_name) { + _fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); + _need_close = true; +@@ -1362,7 +1395,7 @@ void ostream_init_log() { + if (DumpLoadedClassList != NULL) { + const char* list_name = make_log_name(DumpLoadedClassList, NULL); + classlist_file = new(ResourceObj::C_HEAP, mtInternal) +- fileStream(list_name); ++ jsaFileStream(list_name); + FREE_C_HEAP_ARRAY(char, list_name, mtInternal); + } + #endif +diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp +index 530c523c..c69289fb 100644 +--- a/hotspot/src/share/vm/utilities/ostream.hpp ++++ b/hotspot/src/share/vm/utilities/ostream.hpp +@@ -214,7 +214,13 @@ class fileStream : public outputStream { + void flush(); + }; + +-CDS_ONLY(extern fileStream* classlist_file;) ++class jsaFileStream : public fileStream { ++ public: ++ jsaFileStream(const char* file_name); ++ ~jsaFileStream(); ++}; ++ ++CDS_ONLY(extern jsaFileStream* classlist_file;) + + // unlike fileStream, fdStream does unbuffered I/O by calling + // open() and write() directly. It is async-safe, but output diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index c69aaea..4659dca 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 7 +Release: 8 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1063,6 +1063,7 @@ Patch134: PS-GC-adding-acquire_size-method-for-PSParallelCompa.patch Patch135: 8223940-Private-key-not-supported-by-chosen-signature.patch Patch136: 8236512-PKCS11-Connection-closed-after-Cipher.doFinal-and-NoPadding.patch Patch137: 8250861-Crash-in-MinINode-Ideal-PhaseGVN-bool.patch +Patch138: add-appcds-file-lock.patch ############################################# # @@ -1481,6 +1482,7 @@ pushd %{top_level_dir_name} %patch135 -p1 %patch136 -p1 %patch137 -p1 +%patch138 -p1 popd @@ -2097,6 +2099,9 @@ require "copy_jdk_configs.lua" %endif %changelog +* Thu Dec 22 2020 kuenking - 1:1.8.0.272-b10.8 +- add add-appcds-file-lock.patch + * Mon Dec 21 2020 noah - 1:1.8.0.272-b10.7 - add a license to this repo -- Gitee From 55fcf26fdf2204a879f82c08c0b0cfa302c456eb Mon Sep 17 00:00:00 2001 From: cruise01 Date: Tue, 22 Dec 2020 16:44:56 +0800 Subject: [PATCH 2/7] I2ADAN: G1 memory uncommit --- ...ed-test-result-caused-by-C2-MergeMem.patch | 2 +- G1-memory-uncommit.patch | 2121 +++++++++++++++++ java-1.8.0-openjdk.spec | 7 +- 3 files changed, 2128 insertions(+), 2 deletions(-) create mode 100755 G1-memory-uncommit.patch diff --git a/8243670-Unexpected-test-result-caused-by-C2-MergeMem.patch b/8243670-Unexpected-test-result-caused-by-C2-MergeMem.patch index 6139bd6..c08b12c 100644 --- a/8243670-Unexpected-test-result-caused-by-C2-MergeMem.patch +++ b/8243670-Unexpected-test-result-caused-by-C2-MergeMem.patch @@ -112,7 +112,7 @@ index 000000000..d4c93b390 +++ b/hotspot/test/compiler/c2/TestReplaceEquivPhis.java @@ -0,0 +1,77 @@ +/* -+ * Copyright (c) 2020, Huawei Technologies Co. Ltd. All rights reserved. ++ * Copyright (c) 2020, Huawei Technologies Co., LTD. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it diff --git a/G1-memory-uncommit.patch b/G1-memory-uncommit.patch new file mode 100755 index 0000000..da20a27 --- /dev/null +++ b/G1-memory-uncommit.patch @@ -0,0 +1,2121 @@ +diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCCause.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCCause.java +index 84f0a4ac..b38ee52e 100644 +--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCCause.java ++++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc_interface/GCCause.java +@@ -54,6 +54,7 @@ public enum GCCause { + + _g1_inc_collection_pause ("G1 Evacuation Pause"), + _g1_humongous_allocation ("G1 Humongous Allocation"), ++ _g1_periodic_gc ("G1 Periodic GC"), + + _shenandoah_allocation_failure_evac ("Allocation Failure During Evacuation"), + _shenandoah_stop_vm ("Stopping VM"), +diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-debug b/hotspot/make/bsd/makefiles/mapfile-vers-debug +index 49a70edc..00651d42 100644 +--- a/hotspot/make/bsd/makefiles/mapfile-vers-debug ++++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug +@@ -230,6 +230,10 @@ + _JVM_SetPrimitiveArrayElement + _JVM_SetSockOpt + _JVM_SetThreadPriority ++ _JVM_AdaptiveHeapSetG1PeriodicGCInterval ++ _JVM_AdaptiveHeapGetG1PeriodicGCInterval ++ _JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold ++ _JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold + _JVM_Sleep + _JVM_Socket + _JVM_SocketAvailable +diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-product b/hotspot/make/bsd/makefiles/mapfile-vers-product +index 50274671..4d51f425 100644 +--- a/hotspot/make/bsd/makefiles/mapfile-vers-product ++++ b/hotspot/make/bsd/makefiles/mapfile-vers-product +@@ -230,6 +230,10 @@ + _JVM_SetPrimitiveArrayElement + _JVM_SetSockOpt + _JVM_SetThreadPriority ++ _JVM_AdaptiveHeapGetG1PeriodicGCInterval ++ _JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold ++ _JVM_AdaptiveHeapSetG1PeriodicGCInterval ++ _JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold + _JVM_Sleep + _JVM_Socket + _JVM_SocketAvailable +diff --git a/hotspot/make/linux/makefiles/mapfile-vers-debug b/hotspot/make/linux/makefiles/mapfile-vers-debug +index 814a32f6..e1bb0c34 100644 +--- a/hotspot/make/linux/makefiles/mapfile-vers-debug ++++ b/hotspot/make/linux/makefiles/mapfile-vers-debug +@@ -233,6 +233,10 @@ SUNWprivate_1.1 { + JVM_SetPrimitiveArrayElement; + JVM_SetSockOpt; + JVM_SetThreadPriority; ++ JVM_AdaptiveHeapSetG1PeriodicGCInterval; ++ JVM_AdaptiveHeapGetG1PeriodicGCInterval; ++ JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold; ++ JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold; + JVM_Sleep; + JVM_Socket; + JVM_SocketAvailable; +diff --git a/hotspot/make/linux/makefiles/mapfile-vers-product b/hotspot/make/linux/makefiles/mapfile-vers-product +index caf9a1ce..f6aba6ef 100644 +--- a/hotspot/make/linux/makefiles/mapfile-vers-product ++++ b/hotspot/make/linux/makefiles/mapfile-vers-product +@@ -233,6 +233,10 @@ SUNWprivate_1.1 { + JVM_SetPrimitiveArrayElement; + JVM_SetSockOpt; + JVM_SetThreadPriority; ++ JVM_AdaptiveHeapSetG1PeriodicGCInterval; ++ JVM_AdaptiveHeapGetG1PeriodicGCInterval; ++ JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold; ++ JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold; + JVM_Sleep; + JVM_Socket; + JVM_SocketAvailable; +diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp +index 4abd2f03..b078bee0 100644 +--- a/hotspot/src/os/aix/vm/os_aix.cpp ++++ b/hotspot/src/os/aix/vm/os_aix.cpp +@@ -4476,6 +4476,10 @@ bool os::is_thread_cpu_time_supported() { + return true; + } + ++double os::get_process_load() { ++ return -1.0; ++} ++ + // System loadavg support. Returns -1 if load average cannot be obtained. + // For now just return the system wide load average (no processor sets). + int os::loadavg(double values[], int nelem) { +diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp +index 46673771..7cd79123 100644 +--- a/hotspot/src/os/bsd/vm/os_bsd.cpp ++++ b/hotspot/src/os/bsd/vm/os_bsd.cpp +@@ -4293,6 +4293,10 @@ bool os::is_thread_cpu_time_supported() { + #endif + } + ++double os::get_process_load() { ++ return -1.0; ++} ++ + // System loadavg support. Returns -1 if load average cannot be obtained. + // Bsd doesn't yet have a (official) notion of processor sets, + // so just return the system wide load average. +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index 5e0c18e6..ad3a82c4 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -38,6 +38,7 @@ + #include "oops/oop.inline.hpp" + #include "os_share_linux.hpp" + #include "osContainer_linux.hpp" ++#include "process_load.hpp" + #include "prims/jniFastGetField.hpp" + #include "prims/jvm.h" + #include "prims/jvm_misc.hpp" +@@ -5889,6 +5890,15 @@ int os::loadavg(double loadavg[], int nelem) { + return ::getloadavg(loadavg, nelem); + } + ++double os::get_process_load() { ++ double u, s; ++ u = get_cpuload_internal(-1, &s, CPU_LOAD_VM_ONLY); ++ if (u < 0) { ++ return -1.0; ++ } ++ return u + s; ++} ++ + void os::pause() { + char filename[MAX_PATH]; + if (PauseAtStartupFile && PauseAtStartupFile[0]) { +diff --git a/hotspot/src/os/linux/vm/process_load.hpp b/hotspot/src/os/linux/vm/process_load.hpp +new file mode 100644 +index 00000000..83800b19 +--- /dev/null ++++ b/hotspot/src/os/linux/vm/process_load.hpp +@@ -0,0 +1,299 @@ ++/* ++ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Oracle designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++#ifndef OS_LINUX_VM_PROCESS_LOAD_HPP ++#define OS_LINUX_VM_PROCESS_LOAD_HPP ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct ticks { ++ uint64_t used; ++ uint64_t usedKernel; ++ uint64_t total; ++}; ++ ++typedef struct ticks ticks; ++ ++typedef enum { ++ CPU_LOAD_VM_ONLY, ++ CPU_LOAD_GLOBAL, ++} CpuLoadTarget; ++ ++static struct perfbuf { ++ int nProcs; ++ ticks jvmTicks; ++ ticks cpuTicks; ++ ticks *cpus; ++} counters; ++ ++static void next_line(FILE *f) { ++ while (fgetc(f) != '\n'); ++} ++ ++/** ++ * Return the total number of ticks since the system was booted. ++ * If the usedTicks parameter is not NULL, it will be filled with ++ * the number of ticks spent on actual processes (user, system or ++ * nice processes) since system boot. Note that this is the total number ++ * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is ++ * n times the number of ticks that has passed in clock time. ++ * ++ * Returns a negative value if the reading of the ticks failed. ++ */ ++static int get_totalticks(int which, ticks *pticks) { ++ FILE *fh; ++ uint64_t userTicks, niceTicks, systemTicks, idleTicks; ++ uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0; ++ int n; ++ ++ if((fh = fopen("/proc/stat", "r")) == NULL) { ++ return -1; ++ } ++ ++ n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " ++ UINT64_FORMAT " " UINT64_FORMAT, ++ &userTicks, &niceTicks, &systemTicks, &idleTicks, ++ &iowTicks, &irqTicks, &sirqTicks); ++ ++ // Move to next line ++ next_line(fh); ++ ++ //find the line for requested cpu faster to just iterate linefeeds? ++ if (which != -1) { ++ int i; ++ for (i = 0; i < which; i++) { ++ if (fscanf(fh, "cpu%*d " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " ++ UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT, ++ &userTicks, &niceTicks, &systemTicks, &idleTicks, ++ &iowTicks, &irqTicks, &sirqTicks) < 4) { ++ fclose(fh); ++ return -2; ++ } ++ next_line(fh); ++ } ++ n = fscanf(fh, "cpu%*d " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " ++ UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT "\n", ++ &userTicks, &niceTicks, &systemTicks, &idleTicks, ++ &iowTicks, &irqTicks, &sirqTicks); ++ } ++ ++ fclose(fh); ++ if (n < 4) { ++ return -2; ++ } ++ ++ pticks->used = userTicks + niceTicks; ++ pticks->usedKernel = systemTicks + irqTicks + sirqTicks; ++ pticks->total = userTicks + niceTicks + systemTicks + idleTicks + ++ iowTicks + irqTicks + sirqTicks; ++ ++ return 0; ++} ++ ++static int vread_statdata(const char *procfile, const char *fmt, va_list args) { ++ FILE *f; ++ int n; ++ char buf[2048]; ++ ++ if ((f = fopen(procfile, "r")) == NULL) { ++ return -1; ++ } ++ ++ if ((n = fread(buf, 1, sizeof(buf), f)) != -1) { ++ char *tmp; ++ ++ buf[n-1] = '\0'; ++ /** skip through pid and exec name. the exec name _could be wacky_ (renamed) and ++ * make scanf go mupp. ++ */ ++ if ((tmp = strrchr(buf, ')')) != NULL) { ++ // skip the ')' and the following space but check that the buffer is long enough ++ tmp += 2; ++ if (tmp < buf + n) { ++ n = vsscanf(tmp, fmt, args); ++ } ++ } ++ } ++ ++ fclose(f); ++ ++ return n; ++} ++ ++static int read_statdata(const char *procfile, const char *fmt, ...) { ++ int n; ++ va_list args; ++ ++ va_start(args, fmt); ++ n = vread_statdata(procfile, fmt, args); ++ va_end(args); ++ return n; ++} ++ ++/** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */ ++static int read_ticks(const char *procfile, uint64_t *userTicks, uint64_t *systemTicks) { ++ return read_statdata(procfile, "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u "UINT64_FORMAT" "UINT64_FORMAT, ++ userTicks, systemTicks ++ ); ++} ++ ++/** ++ * Return the number of ticks spent in any of the processes belonging ++ * to the JVM on any CPU. ++ */ ++static int get_jvmticks(ticks *pticks) { ++ uint64_t userTicks; ++ uint64_t systemTicks; ++ ++ if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) < 0) { ++ return -1; ++ } ++ ++ // get the total ++ if (get_totalticks(-1, pticks) < 0) { ++ return -1; ++ } ++ ++ pticks->used = userTicks; ++ pticks->usedKernel = systemTicks; ++ ++ return 0; ++} ++ ++/** ++ * This method must be called first, before any data can be gathererd. ++ */ ++int perfInit() { ++ static int initialized=1; ++ ++ if (!initialized) { ++ int i; ++ ++ int n = sysconf(_SC_NPROCESSORS_ONLN); ++ if (n <= 0) { ++ n = 1; ++ } ++ ++ counters.cpus = (ticks*)calloc(n,sizeof(ticks)); ++ if (counters.cpus != NULL) { ++ // For the CPU load ++ get_totalticks(-1, &counters.cpuTicks); ++ ++ for (i = 0; i < n; i++) { ++ get_totalticks(i, &counters.cpus[i]); ++ } ++ // For JVM load ++ get_jvmticks(&counters.jvmTicks); ++ initialized = 1; ++ } ++ } ++ ++ return initialized ? 0 : -1; ++} ++ ++static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; ++ ++/** ++ * Return the load of the CPU as a double. 1.0 means the CPU process uses all ++ * available time for user or system processes, 0.0 means the CPU uses all time ++ * being idle. ++ * ++ * Returns a negative value if there is a problem in determining the CPU load. ++ */ ++ ++static double get_cpuload_internal(int which, double *pkernelLoad, CpuLoadTarget target) { ++ uint64_t udiff, kdiff, tdiff; ++ ticks *pticks, tmp; ++ double user_load = -1.0; ++ int failed = 0; ++ ++ *pkernelLoad = 0.0; ++ ++ pthread_mutex_lock(&lock); ++ ++ if(perfInit() == 0) { ++ ++ if (target == CPU_LOAD_VM_ONLY) { ++ pticks = &counters.jvmTicks; ++ } else if (which == -1) { ++ pticks = &counters.cpuTicks; ++ } else { ++ pticks = &counters.cpus[which]; ++ } ++ ++ tmp = *pticks; ++ ++ if (target == CPU_LOAD_VM_ONLY) { ++ if (get_jvmticks(pticks) != 0) { ++ failed = 1; ++ } ++ } else if (get_totalticks(which, pticks) < 0) { ++ failed = 1; ++ } ++ ++ if(!failed) { ++ // seems like we sometimes end up with less kernel ticks when ++ // reading /proc/self/stat a second time, timing issue between cpus? ++ if (pticks->usedKernel < tmp.usedKernel) { ++ kdiff = 0; ++ } else { ++ kdiff = pticks->usedKernel - tmp.usedKernel; ++ } ++ tdiff = pticks->total - tmp.total; ++ udiff = pticks->used - tmp.used; ++ ++ if (tdiff == 0) { ++ user_load = 0; ++ } else { ++ if (tdiff < (udiff + kdiff)) { ++ tdiff = udiff + kdiff; ++ } ++ *pkernelLoad = (kdiff / (double)tdiff); ++ // BUG9044876, normalize return values to sane values ++ *pkernelLoad = MAX(*pkernelLoad, 0.0); ++ *pkernelLoad = MIN(*pkernelLoad, 1.0); ++ ++ user_load = (udiff / (double)tdiff); ++ user_load = MAX(user_load, 0.0); ++ user_load = MIN(user_load, 1.0); ++ } ++ } ++ } ++ pthread_mutex_unlock(&lock); ++ return user_load; ++} ++ ++#endif +diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp +index 9c9de85a..73253843 100644 +--- a/hotspot/src/os/solaris/vm/os_solaris.cpp ++++ b/hotspot/src/os/solaris/vm/os_solaris.cpp +@@ -5709,6 +5709,10 @@ bool os::is_thread_cpu_time_supported() { + } + } + ++double os::get_process_load() { ++ return -1.0; ++} ++ + // System loadavg support. Returns -1 if load average cannot be obtained. + // Return the load average for our processor set if the primitive exists + // (Solaris 9 and later). Otherwise just return system wide loadavg. +diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp +index 74412a3e..e7ff202a 100644 +--- a/hotspot/src/os/windows/vm/os_windows.cpp ++++ b/hotspot/src/os/windows/vm/os_windows.cpp +@@ -4312,6 +4312,10 @@ bool os::is_thread_cpu_time_supported() { + } + } + ++double os::get_process_load() { ++ return -1.0; ++} ++ + // Windows does't provide a loadavg primitive so this is stubbed out for now. + // It does have primitives (PDH API) to get CPU usage and run queue length. + // "\\Processor(_Total)\\% Processor Time", "\\System\\Processor Queue Length" +diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp +index a42b8ec7..98a43ba6 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp +@@ -25,6 +25,7 @@ + #include "precompiled.hpp" + #include "gc_implementation/g1/concurrentG1Refine.hpp" + #include "gc_implementation/g1/concurrentG1RefineThread.hpp" ++#include "gc_implementation/g1/concurrentMarkThread.hpp" + #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" + #include "gc_implementation/g1/g1CollectorPolicy.hpp" + #include "memory/resourceArea.hpp" +@@ -43,7 +44,8 @@ ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *nex + _next(next), + _monitor(NULL), + _cg1r(cg1r), +- _vtime_accum(0.0) ++ _vtime_accum(0.0), ++ _last_periodic_gc_attempt_s(0.0) + { + + // Each thread has its own monitor. The i-th thread is responsible for signalling +@@ -98,6 +100,69 @@ void ConcurrentG1RefineThread::sample_young_list_rs_lengths() { + } + } + ++bool ConcurrentG1RefineThread::should_start_periodic_gc() { ++ // If we are currently in a concurrent mark we are going to uncommit memory soon. ++ if (G1CollectedHeap::heap()->concurrent_mark()->cmThread()->during_cycle()) { ++ if (G1UncommitLog) { ++ gclog_or_tty->print_cr("Concurrent cycle in progress. Skipping."); ++ } ++ return false; ++ } ++ ++ // Check if enough time has passed since the last GC. ++ uintx time_since_last_gc; ++ if ((time_since_last_gc = (uintx)Universe::heap()->millis_since_last_gc()) < G1PeriodicGCInterval) { ++ if (G1UncommitLog) { ++ gclog_or_tty->print_cr("Last GC occurred " UINTX_FORMAT "ms before which is below threshold " UINTX_FORMAT "ms. Skipping.", ++ time_since_last_gc, G1PeriodicGCInterval); ++ } ++ return false; ++ } ++ ++ return true; ++} ++ ++void ConcurrentG1RefineThread::check_for_periodic_gc() { ++ if (!G1Uncommit) { ++ return; ++ } ++ ++ assert(G1PeriodicGCInterval > 0, "just checking"); ++ double recent_load = -1.0; ++ G1CollectedHeap* g1h = G1CollectedHeap::heap(); ++ G1CollectorPolicy* g1p = g1h->g1_policy(); ++ if (G1PeriodicGCLoadThreshold) { ++ // Sample process load and store it ++ if (G1PeriodicGCProcessLoad) { ++ recent_load = os::get_process_load() * 100; ++ } ++ if (recent_load < 0) { ++ // Fallback to os load ++ G1PeriodicGCProcessLoad = false; ++ if (os::loadavg(&recent_load, 1) != -1) { ++ static int cpu_count = os::active_processor_count(); ++ assert(cpu_count > 0, "just checking"); ++ recent_load = recent_load * 100 / cpu_count; ++ } ++ } ++ if (recent_load >= 0) { ++ g1p->add_os_load(recent_load); ++ } ++ } ++ ++ double now = os::elapsedTime(); ++ if (now - _last_periodic_gc_attempt_s > G1PeriodicGCInterval / 1000.0) { ++ if (G1UncommitLog) { ++ recent_load < 0 ? gclog_or_tty->print_cr("Checking for periodic GC.") ++ : gclog_or_tty->print_cr("Checking for periodic GC. Current load %1.2f. Heap total " UINT32_FORMAT " free " UINT32_FORMAT, recent_load, g1h->_hrm.length(), g1h->_hrm.num_free_regions()); ++ } ++ if (should_start_periodic_gc()) { ++ g1p->set_periodic_gc(); ++ } ++ _last_periodic_gc_attempt_s = now; ++ } ++} ++ + void ConcurrentG1RefineThread::run_young_rs_sampling() { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + _vtime_start = os::elapsedVTime(); +@@ -110,6 +175,8 @@ void ConcurrentG1RefineThread::run_young_rs_sampling() { + _vtime_accum = 0.0; + } + ++ check_for_periodic_gc(); ++ + MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + if (_should_terminate) { + break; +diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp +index 05a8dc44..8fa52137 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.hpp +@@ -42,6 +42,8 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { + uint _worker_id; + uint _worker_id_offset; + ++ double _last_periodic_gc_attempt_s; ++ + // The refinement threads collection is linked list. A predecessor can activate a successor + // when the number of the rset update buffer crosses a certain threshold. A successor + // would self-deactivate when the number of the buffers falls below the threshold. +@@ -68,6 +70,9 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { + void activate(); + void deactivate(); + ++ void check_for_periodic_gc(); ++ bool should_start_periodic_gc(); ++ + public: + virtual void run(); + // Constructor +diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +index d782c892..a69db6eb 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +@@ -1354,6 +1354,7 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { + satb_mq_set.set_active_all_threads(false, /* new active value */ + true /* expected_active */); + ++ g1h->extract_uncommit_list(); + if (VerifyDuringGC) { + HandleMark hm; // handle scope + Universe::heap()->prepare_for_verify(); +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp +index a90c15ea..b2d3b282 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp +@@ -47,15 +47,15 @@ G1BlockOffsetTable::block_start_const(const void* addr) const { + } + } + +-#define check_index(index, msg) \ +- assert((index) < (_reserved.word_size() >> LogN_words), \ +- err_msg("%s - index: "SIZE_FORMAT", _vs.committed_size: "SIZE_FORMAT, \ +- msg, (index), (_reserved.word_size() >> LogN_words))); \ +- assert(G1CollectedHeap::heap()->is_in_exact(address_for_index_raw(index)), \ +- err_msg("Index "SIZE_FORMAT" corresponding to "PTR_FORMAT \ +- " (%u) is not in committed area.", \ +- (index), \ +- p2i(address_for_index_raw(index)), \ ++#define check_index(index, msg) \ ++ assert((index) < (_reserved.word_size() >> LogN_words), \ ++ err_msg("%s - index: "SIZE_FORMAT", _vs.committed_size: "SIZE_FORMAT, \ ++ msg, (index), (_reserved.word_size() >> LogN_words))); \ ++ assert(!G1Uncommit && G1CollectedHeap::heap()->is_in_exact(address_for_index_raw(index)) || G1Uncommit, \ ++ err_msg("Index "SIZE_FORMAT" corresponding to "PTR_FORMAT \ ++ " (%u) is not in committed area.", \ ++ (index), \ ++ p2i(address_for_index_raw(index)), \ + G1CollectedHeap::heap()->addr_to_region(address_for_index_raw(index)))); + + u_char G1BlockOffsetSharedArray::offset_array(size_t index) const { +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +index 91ad2e98..722e5985 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +@@ -1873,6 +1873,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : + _dirty_cards_region_list(NULL), + _worker_cset_start_region(NULL), + _worker_cset_start_region_time_stamp(NULL), ++ _uncommit_thread(NULL), + _gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()), + _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()), + _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()), +@@ -1952,6 +1953,16 @@ jint G1CollectedHeap::initialize() { + size_t max_byte_size = collector_policy()->max_heap_byte_size(); + size_t heap_alignment = collector_policy()->heap_alignment(); + ++ if (G1Uncommit) { ++ if (G1PeriodicGCInterval == 0) { ++ vm_exit_during_initialization(err_msg("G1Uncommit requires G1PeriodicGCInterval > 0")); ++ return JNI_EINVAL; ++ } ++ if (G1PeriodicGCLoadThreshold < 0 || G1PeriodicGCLoadThreshold > 100) { ++ vm_exit_during_initialization(err_msg("G1Uncommit requires G1PeriodicGCLoadThreshold >= 0 and <= 100")); ++ return JNI_EINVAL; ++ } ++ } + // Ensure that the sizes are properly aligned. + Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); + Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); +@@ -2148,6 +2159,30 @@ void G1CollectedHeap::stop() { + if (G1StringDedup::is_enabled()) { + G1StringDedup::stop(); + } ++ if (G1Uncommit && _uncommit_thread != NULL) { ++ _uncommit_thread->stop(); ++ PeriodicGC::stop(); ++ } ++} ++ ++void G1CollectedHeap::check_trigger_periodic_gc() { ++ if (g1_policy()->should_trigger_periodic_gc()) { ++ collect(GCCause::_g1_periodic_collection); ++ } ++} ++ ++void G1CollectedHeap::init_periodic_gc_thread() { ++ if (_uncommit_thread == NULL && G1Uncommit) { ++ PeriodicGC::start(); ++ _uncommit_thread = new G1UncommitThread(); ++ } ++} ++ ++void G1CollectedHeap::extract_uncommit_list() { ++ if (g1_policy()->can_extract_uncommit_list()) { ++ uint count = _hrm.extract_uncommit_list(); ++ g1_policy()->record_extract_uncommit_list(count); ++ } + } + + size_t G1CollectedHeap::conservative_max_heap_alignment() { +@@ -2335,6 +2370,7 @@ bool G1CollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) { + case GCCause::_g1_humongous_allocation: return true; + case GCCause::_update_allocation_context_stats_inc: return true; + case GCCause::_wb_conc_mark: return true; ++ case GCCause::_g1_periodic_collection: return true; + default: return false; + } + } +@@ -2528,6 +2564,7 @@ void G1CollectedHeap::collect(GCCause::Cause cause) { + return; + } else { + if (cause == GCCause::_gc_locker || cause == GCCause::_wb_young_gc ++ || cause == GCCause::_g1_periodic_collection + DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) { + + // Schedule a standard evacuation pause. We're setting word_size +@@ -2925,7 +2962,14 @@ size_t G1CollectedHeap::max_capacity() const { + + jlong G1CollectedHeap::millis_since_last_gc() { + // assert(false, "NYI"); +- return 0; ++ jlong ret_val = (os::javaTimeNanos() / NANOSECS_PER_MILLISEC) - ++ _g1_policy->collection_pause_end_millis(); ++ if (ret_val < 0) { ++ gclog_or_tty->print_cr("millis_since_last_gc() would return : " JLONG_FORMAT ++ ". returning zero instead.", ret_val); ++ return 0; ++ } ++ return ret_val; + } + + void G1CollectedHeap::prepare_for_verify() { +@@ -4033,6 +4077,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { + + + double pause_start_sec = os::elapsedTime(); ++ g1_policy()->record_gc_start(pause_start_sec); + g1_policy()->phase_times()->note_gc_start(active_workers, mark_in_progress()); + log_gc_header(); + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +index 4783cbde..bde0ca4d 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +@@ -35,6 +35,7 @@ + #include "gc_implementation/g1/g1InCSetState.hpp" + #include "gc_implementation/g1/g1MonitoringSupport.hpp" + #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" ++#include "gc_implementation/g1/g1UncommitThread.hpp" + #include "gc_implementation/g1/g1YCTypes.hpp" + #include "gc_implementation/g1/heapRegionManager.hpp" + #include "gc_implementation/g1/heapRegionSet.hpp" +@@ -74,8 +75,10 @@ class GenerationCounters; + class STWGCTimer; + class G1NewTracer; + class G1OldTracer; ++class G1UncommitThread; + class EvacuationFailedInfo; + class nmethod; ++class ScanRSClosure; + + typedef OverflowTaskQueue RefToScanQueue; + typedef GenericTaskQueueSet RefToScanQueueSet; +@@ -186,8 +189,12 @@ class G1CollectedHeap : public SharedHeap { + friend class SurvivorGCAllocRegion; + friend class OldGCAllocRegion; + friend class G1Allocator; ++ friend class G1CollectorPolicy; + friend class G1DefaultAllocator; + friend class G1ResManAllocator; ++ friend class ScanRSClosure; ++ friend class G1UncommitThread; ++ friend class ConcurrentG1RefineThread; + + // Closures used in implementation. + template +@@ -210,6 +217,7 @@ class G1CollectedHeap : public SharedHeap { + friend class G1ParCleanupCTTask; + + friend class G1FreeHumongousRegionClosure; ++ friend class FreeRegionList; + // Other related classes. + friend class G1MarkSweep; + +@@ -266,6 +274,8 @@ private: + // Class that handles the different kinds of allocations. + G1Allocator* _allocator; + ++ G1UncommitThread* _uncommit_thread; ++ + // Statistics for each allocation context + AllocationContextStats _allocation_context_stats; + +@@ -1002,6 +1012,10 @@ public: + + void set_refine_cte_cl_concurrency(bool concurrent); + ++ void check_trigger_periodic_gc(); ++ void init_periodic_gc_thread(); ++ void extract_uncommit_list(); ++ + RefToScanQueue *task_queue(int i) const; + + // A set of cards where updates happened during the GC +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +index b416917f..05a270d2 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +@@ -93,6 +93,9 @@ G1CollectorPolicy::G1CollectorPolicy() : + _concurrent_mark_cleanup_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), + + _alloc_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)), ++ _heap_size_seq(new TruncatedSeq(TruncatedSeqLength)), ++ _os_load_seq(new TruncatedSeq(TruncatedSeqLength)), ++ _gc_count_seq(new TruncatedSeq(TruncatedSeqLength)), + _prev_collection_pause_end_ms(0.0), + _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)), + _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), +@@ -113,6 +116,13 @@ G1CollectorPolicy::G1CollectorPolicy() : + _pause_time_target_ms((double) MaxGCPauseMillis), + + _gcs_are_young(true), ++ _periodic_gc(false), ++ _last_uncommit_attempt_s(0.0), ++ _os_load(-1.0), ++ _uncommit_start_time(0), ++ _gc_count_cancel_extract(false), ++ _gc_count(0), ++ _gc_count_minute(0), + + _during_marking(false), + _in_marking_window(false), +@@ -153,7 +163,8 @@ G1CollectorPolicy::G1CollectorPolicy() : + _inc_cset_recorded_rs_lengths_diffs(0), + _inc_cset_predicted_elapsed_time_ms(0.0), + _inc_cset_predicted_elapsed_time_ms_diffs(0.0), +- ++ _collection_pause_end_millis(os::javaTimeNanos() / NANOSECS_PER_MILLISEC), ++ _extract_uncommit_list(0), + #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away + #pragma warning( disable:4355 ) // 'this' : used in base member initializer list + #endif // _MSC_VER +@@ -976,6 +987,8 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, Evacua + } + #endif // PRODUCT + ++ _collection_pause_end_millis = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; ++ + last_pause_included_initial_mark = during_initial_mark_pause(); + if (last_pause_included_initial_mark) { + record_concurrent_mark_init_end(0.0); +@@ -1204,6 +1217,7 @@ void G1CollectorPolicy::record_heap_size_info_at_start(bool full) { + _heap_capacity_bytes_before_gc = _g1->capacity(); + _heap_used_bytes_before_gc = _g1->used(); + _cur_collection_pause_used_regions_at_start = _g1->num_used_regions(); ++ _heap_size_seq->add(_cur_collection_pause_used_regions_at_start); + + _eden_capacity_bytes_before_gc = + (_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc; +@@ -1247,6 +1261,13 @@ void G1CollectorPolicy::print_detailed_heap_transition(bool full) { + EXT_SIZE_PARAMS(heap_used_bytes_after_gc), + EXT_SIZE_PARAMS(heap_capacity_bytes_after_gc)); + ++ if (_extract_uncommit_list) { ++ gclog_or_tty->print(" [Uncommit list " UINTX_FORMAT ", remaining " UINTX_FORMAT ", free list " UINTX_FORMAT "]", ++ _extract_uncommit_list, ++ _g1->_hrm.length(), ++ _g1->_hrm.num_free_regions()); ++ _extract_uncommit_list = 0; ++ } + if (full) { + MetaspaceAux::print_metaspace_change(_metaspace_used_bytes_before_gc); + } +@@ -2160,6 +2181,53 @@ void G1CollectorPolicy::finalize_cset(double target_pause_time_ms, EvacuationInf + evacuation_info.set_collectionset_regions(cset_region_length()); + } + ++void G1CollectorPolicy::record_gc_start(double curr_sec) { ++ if (_uncommit_start_time == 0) { ++ _uncommit_start_time = curr_sec + G1UncommitDelay; ++ } ++ long curr = curr_sec / 60; ++ if (curr > _gc_count_minute) { ++ int diff = curr - _gc_count_minute; ++ _gc_count_seq->add(_gc_count); ++ for (int i = 1; i < diff; i++) { ++ _gc_count_seq->add(0.0); ++ } ++ _gc_count_minute = curr; ++ double gc_count_expected = get_new_prediction(_gc_count_seq); ++ // Considering the test result, 15000 is an appropriate value for G1PeriodicGCInterval. ++ _gc_count_cancel_extract = gc_count_expected > MIN2(4.0, 60000.0 / G1PeriodicGCInterval); ++ _gc_count = 0; ++ } ++ _gc_count++; ++} ++ ++bool G1CollectorPolicy::should_trigger_periodic_gc() { ++ if (G1PeriodicGCLoadThreshold && _os_load > G1PeriodicGCLoadThreshold) { ++ _periodic_gc = false; ++ } else if (_periodic_gc) { ++ _periodic_gc = false; ++ return true; ++ } ++ return false; ++} ++ ++bool G1CollectorPolicy::can_extract_uncommit_list() { ++ double now = os::elapsedTime(); ++ if (G1Uncommit && now > _uncommit_start_time) { ++ if (G1PeriodicGCLoadThreshold && _os_load > G1PeriodicGCLoadThreshold) { ++ return false; ++ } ++ G1CollectedHeap* g1h = G1CollectedHeap::heap(); ++ if (!_gc_count_cancel_extract || now >= (g1h->millis_since_last_gc() + G1PeriodicGCInterval) / 1000.0) { ++ if (now - _last_uncommit_attempt_s >= G1PeriodicGCInterval / 1000.0) { ++ _last_uncommit_attempt_s = now; ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ + void TraceGen0TimeData::record_start_collection(double time_to_stop_the_world_ms) { + if(TraceGen0Time) { + _all_stop_world_times_ms.add(time_to_stop_the_world_ms); +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +index 02217ce4..1c918070 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +@@ -183,6 +183,7 @@ private: + + CollectionSetChooser* _collectionSetChooser; + ++ jlong _collection_pause_end_millis; + double _full_collection_start_sec; + uint _cur_collection_pause_used_regions_at_start; + +@@ -243,6 +244,9 @@ private: + TruncatedSeq* _constant_other_time_ms_seq; + TruncatedSeq* _young_other_cost_per_region_ms_seq; + TruncatedSeq* _non_young_other_cost_per_region_ms_seq; ++ TruncatedSeq* _heap_size_seq; ++ TruncatedSeq* _os_load_seq; ++ TruncatedSeq* _gc_count_seq; + + TruncatedSeq* _pending_cards_seq; + TruncatedSeq* _rs_lengths_seq; +@@ -264,6 +268,8 @@ private: + + uint _free_regions_at_end_of_collection; + ++ uint _extract_uncommit_list; ++ + size_t _recorded_rs_lengths; + size_t _max_rs_lengths; + double _sigma; +@@ -300,9 +306,21 @@ private: + + size_t _pending_cards; + ++ size_t _gc_count; ++ long _gc_count_minute; ++ bool _gc_count_cancel_extract; ++ ++ volatile bool _periodic_gc; ++ double _last_uncommit_attempt_s; ++ volatile double _os_load; ++ double _uncommit_start_time; + public: + // Accessors + ++ void set_periodic_gc() { _periodic_gc = true; } ++ bool can_extract_uncommit_list(); ++ bool should_trigger_periodic_gc(); ++ + void set_region_eden(HeapRegion* hr, int young_index_in_cset) { + hr->set_eden(); + hr->install_surv_rate_group(_short_lived_surv_rate_group); +@@ -328,6 +346,17 @@ public: + _max_rs_lengths = rs_lengths; + } + ++ size_t predict_heap_size_seq() { ++ return (size_t) get_new_prediction(_heap_size_seq); ++ } ++ ++ void add_os_load(double load) { ++ _os_load_seq->add(load); ++ _os_load = get_new_prediction(_os_load_seq); ++ } ++ ++ void record_gc_start(double sec); ++ + size_t predict_rs_length_diff() { + return (size_t) get_new_prediction(_rs_length_diff_seq); + } +@@ -475,6 +504,8 @@ public: + return _short_lived_surv_rate_group->accum_surv_rate_pred(age); + } + ++ jlong collection_pause_end_millis() { return _collection_pause_end_millis; } ++ + private: + // Statistics kept per GC stoppage, pause or full. + TruncatedSeq* _recent_prev_end_times_for_all_gcs_sec; +@@ -706,6 +737,8 @@ public: + void record_stop_world_start(); + void record_concurrent_pause(); + ++ void record_extract_uncommit_list(uint count) { _extract_uncommit_list = count; } ++ + // Record how much space we copied during a GC. This is typically + // called when a GC alloc region is being retired. + void record_bytes_copied_during_gc(size_t bytes) { +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +index da417fb7..3066f9e6 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +@@ -206,6 +206,9 @@ public: + #endif + + HeapRegion* card_region = _g1h->heap_region_containing(card_start); ++ if (!_g1h->_hrm.is_available(card_region->hrm_index())) { ++ continue; ++ } + _cards++; + + if (!card_region->is_on_dirty_cards_region_list()) { +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1UncommitThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1UncommitThread.cpp +new file mode 100644 +index 00000000..37bdbdb6 +--- /dev/null ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1UncommitThread.cpp +@@ -0,0 +1,170 @@ ++/* ++ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++ ++#include "gc_implementation/g1/g1UncommitThread.hpp" ++#include "gc_implementation/g1/g1_globals.hpp" ++#include "runtime/javaCalls.hpp" ++#include "runtime/os.hpp" ++ ++#ifdef _WINDOWS ++#pragma warning(disable : 4355) ++#endif ++ ++volatile bool PeriodicGC::_should_terminate = false; ++JavaThread* PeriodicGC::_thread = NULL; ++Monitor* PeriodicGC::_monitor = NULL; ++ ++bool PeriodicGC::has_error(TRAPS, const char* error) { ++ if (HAS_PENDING_EXCEPTION) { ++ tty->print_cr("%s", error); ++ java_lang_Throwable::print(PENDING_EXCEPTION, tty); ++ tty->cr(); ++ CLEAR_PENDING_EXCEPTION; ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++void PeriodicGC::start() { ++ _monitor = new Monitor(Mutex::nonleaf, "PeriodicGC::_monitor", Mutex::_allow_vm_block_flag); ++ ++ EXCEPTION_MARK; ++ Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK); ++ instanceKlassHandle klass (THREAD, k); ++ instanceHandle thread_oop = klass->allocate_instance_handle(CHECK); ++ ++ const char thread_name[] = "periodic gc timer"; ++ Handle string = java_lang_String::create_from_str(thread_name, CHECK); ++ ++ // Initialize thread_oop to put it into the system threadGroup ++ Handle thread_group (THREAD, Universe::system_thread_group()); ++ JavaValue result(T_VOID); ++ JavaCalls::call_special(&result, thread_oop, ++ klass, ++ vmSymbols::object_initializer_name(), ++ vmSymbols::threadgroup_string_void_signature(), ++ thread_group, ++ string, ++ THREAD); ++ if (has_error(THREAD, "Exception in VM (PeriodicGC::start) : ")) { ++ vm_exit_during_initialization("Cannot create periodic gc timer thread."); ++ return; ++ } ++ ++ KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass()); ++ JavaCalls::call_special(&result, ++ thread_group, ++ group, ++ vmSymbols::add_method_name(), ++ vmSymbols::thread_void_signature(), ++ thread_oop, // ARG 1 ++ THREAD); ++ if (has_error(THREAD, "Exception in VM (PeriodicGC::start) : ")) { ++ vm_exit_during_initialization("Cannot create periodic gc timer thread."); ++ return; ++ } ++ ++ { ++ MutexLocker mu(Threads_lock); ++ _thread = new JavaThread(&PeriodicGC::timer_thread_entry); ++ if (_thread == NULL || _thread->osthread() == NULL) { ++ vm_exit_during_initialization("Cannot create PeriodicGC timer thread. Out of system resources."); ++ } ++ ++ java_lang_Thread::set_thread(thread_oop(), _thread); ++ java_lang_Thread::set_daemon(thread_oop()); ++ _thread->set_threadObj(thread_oop()); ++ Threads::add(_thread); ++ Thread::start(_thread); ++ } ++} ++ ++void PeriodicGC::timer_thread_entry(JavaThread* thread, TRAPS) { ++ while(!_should_terminate) { ++ assert(!SafepointSynchronize::is_at_safepoint(), "PeriodicGC timer thread is a JavaThread"); ++ G1CollectedHeap::heap()->check_trigger_periodic_gc(); ++ ++ MutexLockerEx x(_monitor); ++ if (_should_terminate) { ++ break; ++ } ++ _monitor->wait(false /* no_safepoint_check */, 200); ++ } ++} ++ ++void PeriodicGC::stop() { ++ _should_terminate = true; ++ { ++ MutexLockerEx ml(_monitor, Mutex::_no_safepoint_check_flag); ++ _monitor->notify(); ++ } ++} ++ ++G1UncommitThread::G1UncommitThread() : ++ ConcurrentGCThread() { ++ if (os::create_thread(this, os::cgc_thread)) { ++ int native_prio; ++ if (G1UncommitThreadPriority) { ++ native_prio = os::java_to_os_priority[CriticalPriority]; ++ } else { ++ native_prio = os::java_to_os_priority[NearMaxPriority]; ++ } ++ os::set_native_priority(this, native_prio); ++ if (!_should_terminate && !DisableStartThread) { ++ os::start_thread(this); ++ } ++ } ++ if (G1UncommitLog) { ++ gclog_or_tty->print_cr("Periodic GC Thread start"); ++ } ++} ++ ++G1UncommitThread::~G1UncommitThread() { ++ // This is here so that super is called. ++} ++ ++void G1UncommitThread::run() { ++ G1CollectedHeap* heap = G1CollectedHeap::heap(); ++ while (!_should_terminate) { ++ heap->_hrm.free_uncommit_list_memory(); ++ os::sleep(this, G1PeriodicGCInterval / 10, false); ++ } ++ terminate(); ++} ++ ++void G1UncommitThread::stop() { ++ { ++ MutexLockerEx ml(Terminator_lock); ++ _should_terminate = true; ++ } ++ { ++ MutexLockerEx ml(Terminator_lock); ++ while (!_has_terminated) { ++ Terminator_lock->wait(); ++ } ++ } ++} +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1UncommitThread.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1UncommitThread.hpp +new file mode 100644 +index 00000000..883a9a41 +--- /dev/null ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1UncommitThread.hpp +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 2013, 2018, Red Hat, Inc. All rights reserved. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef SHARE_VM_GC_G1_G1CONCURRENTTHREAD_HPP ++#define SHARE_VM_GC_G1_G1CONCURRENTTHREAD_HPP ++ ++#include "gc_implementation/shared/concurrentGCThread.hpp" ++#include "gc_implementation/g1/g1CollectedHeap.hpp" ++#include "gc_implementation/g1/heapRegionSet.hpp" ++ ++class PeriodicGC : AllStatic { ++private: ++ volatile static bool _should_terminate; ++ static JavaThread* _thread; ++ static Monitor* _monitor; ++ ++public: ++ // Timer thread entry ++ static void timer_thread_entry(JavaThread* thread, TRAPS); ++ static void start(); ++ static void stop(); ++ static bool has_error(TRAPS, const char* error); ++}; ++ ++class G1UncommitThread: public ConcurrentGCThread { ++ friend class VMStructs; ++ ++public: ++ // Constructor ++ G1UncommitThread(); ++ ~G1UncommitThread(); ++ ++ void run(); ++ void stop(); ++ ++ char* name() const { return (char*)"G1UncommitThread";} ++}; ++ ++#endif // SHARE_VM_GC_G1_G1CONCURRENTTHREAD_HPP +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +index e24cc959..db7ddece 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +@@ -328,7 +328,37 @@ + "Verify the code root lists attached to each heap region.") \ + \ + develop(bool, G1VerifyBitmaps, false, \ +- "Verifies the consistency of the marking bitmaps") ++ "Verifies the consistency of the marking bitmaps") \ ++ \ ++ product(bool, G1Uncommit, false, \ ++ "Allow G1 to uncommit unused memory.") \ ++ \ ++ product(bool, G1UncommitLog, false, \ ++ "Enable G1 uncommit logs.") \ ++ \ ++ manageable(uintx, G1PeriodicGCInterval, 15000, \ ++ "Number of milliseconds after a previous GC to wait before " \ ++ "triggering a periodic gc. A value of zero disables periodically "\ ++ "enforced gc cycles.") \ ++ \ ++ manageable(uintx, G1PeriodicGCLoadThreshold, 10, \ ++ "Percentage of process load or system load." \ ++ "Above this value cancels a given periodic GC." \ ++ "A value of zero disables load check.") \ ++ \ ++ experimental(bool, G1PeriodicGCProcessLoad, true, \ ++ "if true, use process load, else use system load. which is" \ ++ "the 1m value of getloadavg() / CPU core number.") \ ++ \ ++ experimental(bool, G1UncommitThreadPriority, false, \ ++ "G1 uncommit thread runs at critical scheduling priority.") \ ++ \ ++ experimental(double, G1UncommitPercent, 0.1, \ ++ "Percent of free regions to uncommit for one uncommit cycle.") \ ++ \ ++ experimental(uintx, G1UncommitDelay, 50, \ ++ "Starup delay in seconds for periodic uncommit.") \ ++ \ + + G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +index f0e24811..32f8b198 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +@@ -310,7 +310,8 @@ HeapRegion::HeapRegion(uint hrm_index, + #ifdef ASSERT + _containing_set(NULL), + #endif // ASSERT +- _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1), ++ _in_uncommit_list(false), ++ _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1), + _rem_set(NULL), _recorded_rs_length(0), _predicted_elapsed_time_ms(0), + _predicted_bytes_to_copy(0) + { +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +index b1f94fb9..27b1048f 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +@@ -227,6 +227,9 @@ class HeapRegion: public G1OffsetTableContigSpace { + // For the start region of a humongous sequence, it's original end(). + HeapWord* _orig_end; + ++ // True iff the region is in current uncommit_list. ++ bool _in_uncommit_list; ++ + // True iff the region is in current collection_set. + bool _in_collection_set; + +@@ -429,6 +432,8 @@ class HeapRegion: public G1OffsetTableContigSpace { + return _humongous_start_region; + } + ++ void set_uncommit_list(bool in) { _in_uncommit_list = in; } ++ bool in_uncommit_list() { return _in_uncommit_list; } + // Return the number of distinct regions that are covered by this region: + // 1 if the region is not humongous, >= 1 if the region is humongous. + uint region_num() const { +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp +index 49c231d8..842550d2 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.cpp +@@ -53,12 +53,25 @@ void HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage, + + _available_map.resize(_regions.length(), false); + _available_map.clear(); ++ _uncommit_list_filled = false; + } + + bool HeapRegionManager::is_available(uint region) const { ++ HeapRegion* hr = _regions.get_by_index(region); ++ if (hr != NULL && hr->in_uncommit_list()) { ++ return false; ++ } + return _available_map.at(region); + } + ++bool HeapRegionManager::can_expand(uint region) const { ++ HeapRegion* hr = _regions.get_by_index(region); ++ if (hr != NULL && hr->in_uncommit_list()) { ++ return false; ++ } ++ return !_available_map.at(region); ++} ++ + #ifdef ASSERT + bool HeapRegionManager::is_free(HeapRegion* hr) const { + return _free_list.contains(hr); +@@ -77,7 +90,7 @@ void HeapRegionManager::commit_regions(uint index, size_t num_regions) { + guarantee(num_regions > 0, "Must commit more than zero regions"); + guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions"); + +- _num_committed += (uint)num_regions; ++ Atomic::add((int)num_regions, (volatile int*)&_num_committed); + + _heap_mapper->commit_regions(index, num_regions); + +@@ -103,9 +116,9 @@ void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) { + } + } + +- _num_committed -= (uint)num_regions; +- ++ Atomic::add(-num_regions, (volatile int*)&_num_committed); + _available_map.par_clear_range(start, start + num_regions, BitMap::unknown_range); ++ + _heap_mapper->uncommit_regions(start, num_regions); + + // Also uncommit auxiliary data +@@ -198,7 +211,7 @@ uint HeapRegionManager::find_contiguous(size_t num, bool empty_only) { + + while (length_found < num && cur < max_length()) { + HeapRegion* hr = _regions.get_by_index(cur); +- if ((!empty_only && !is_available(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) { ++ if ((!empty_only && can_expand(cur)) || (is_available(cur) && hr != NULL && hr->is_empty())) { + // This region is a potential candidate for allocation into. + length_found++; + } else { +@@ -213,7 +226,7 @@ uint HeapRegionManager::find_contiguous(size_t num, bool empty_only) { + for (uint i = found; i < (found + num); i++) { + HeapRegion* hr = _regions.get_by_index(i); + // sanity check +- guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()), ++ guarantee((!empty_only && can_expand(i)) || (is_available(i) && hr != NULL && hr->is_empty()), + err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT + " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr))); + } +@@ -239,7 +252,8 @@ void HeapRegionManager::iterate(HeapRegionClosure* blk) const { + uint len = max_length(); + + for (uint i = 0; i < len; i++) { +- if (!is_available(i)) { ++ HeapRegion* r = _regions.get_by_index(i); ++ if (r != NULL && r->in_uncommit_list() || !_available_map.at(i)) { + continue; + } + guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i)); +@@ -265,15 +279,15 @@ uint HeapRegionManager::find_unavailable_from_idx(uint start_idx, uint* res_idx) + return num_regions; + } + *res_idx = cur; +- while (cur < max_length() && !is_available(cur)) { ++ while (cur < max_length() && can_expand(cur)) { + cur++; + } + num_regions = cur - *res_idx; + #ifdef ASSERT + for (uint i = *res_idx; i < (*res_idx + num_regions); i++) { +- assert(!is_available(i), "just checking"); ++ assert(can_expand(i), "just checking"); + } +- assert(cur == max_length() || num_regions == 0 || is_available(cur), ++ assert(cur == max_length() || num_regions == 0 || (!G1Uncommit && is_available(cur)) || G1Uncommit, + err_msg("The region at the current position %u must be available or at the end of the heap.", cur)); + #endif + return num_regions; +@@ -294,10 +308,10 @@ void HeapRegionManager::par_iterate(HeapRegionClosure* blk, uint worker_id, uint + const uint index = (start_index + count) % _allocated_heapregions_length; + assert(0 <= index && index < _allocated_heapregions_length, "sanity"); + // Skip over unavailable regions +- if (!is_available(index)) { ++ HeapRegion* r = _regions.get_by_index(index); ++ if (r != NULL && r->in_uncommit_list() || !_available_map.at(index)) { + continue; + } +- HeapRegion* r = _regions.get_by_index(index); + // We'll ignore "continues humongous" regions (we'll process them + // when we come across their corresponding "start humongous" + // region) and regions already claimed. +@@ -425,12 +439,12 @@ void HeapRegionManager::verify() { + uint num_committed = 0; + HeapWord* prev_end = heap_bottom(); + for (uint i = 0; i < _allocated_heapregions_length; i++) { +- if (!is_available(i)) { ++ HeapRegion* hr = _regions.get_by_index(i); ++ if (hr != NULL && hr->in_uncommit_list() || !_available_map.at(i)) { + prev_committed = false; + continue; + } + num_committed++; +- HeapRegion* hr = _regions.get_by_index(i); + guarantee(hr != NULL, err_msg("invariant: i: %u", i)); + guarantee(!prev_committed || hr->bottom() == prev_end, + err_msg("invariant i: %u " HR_FORMAT " prev_end: " PTR_FORMAT, +@@ -454,10 +468,38 @@ void HeapRegionManager::verify() { + guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i)); + } + +- guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed)); ++ guarantee((!G1Uncommit && num_committed == _num_committed) || G1Uncommit, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed)); + _free_list.verify(); + } + ++void HeapRegionManager::free_uncommit_list_memory() { ++ if (_uncommit_list_filled) { ++ _uncommit_list.remove_all(true); ++ OrderAccess::storestore(); ++ _uncommit_list_filled = false; ++ } ++} ++ ++uint HeapRegionManager::extract_uncommit_list() ++{ ++ assert_at_safepoint(true /* should_be_vm_thread */); ++ if (!_uncommit_list_filled) { ++ G1CollectedHeap* g1h = G1CollectedHeap::heap(); ++ uint dest = ((G1CollectorPolicy*)g1h->collector_policy())->predict_heap_size_seq(); ++ ++ if (dest < _num_committed) { ++ uint num_regions_to_remove = (_num_committed - dest) * G1UncommitPercent; ++ if (num_regions_to_remove >= 1 && num_regions_to_remove < _free_list.length()) { ++ int count = _free_list.move_regions_to(&_uncommit_list, num_regions_to_remove); ++ OrderAccess::storestore(); ++ _uncommit_list_filled = true; ++ return count; ++ } ++ } ++ } ++ return 0; ++} ++ + #ifndef PRODUCT + void HeapRegionManager::verify_optional() { + verify(); +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.hpp +index 83996f71..71512218 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionManager.hpp +@@ -67,6 +67,7 @@ class G1HeapRegionTable : public G1BiasedMappedArray { + + class HeapRegionManager: public CHeapObj { + friend class VMStructs; ++ friend class FreeRegionList; + + G1HeapRegionTable _regions; + +@@ -78,6 +79,8 @@ class HeapRegionManager: public CHeapObj { + G1RegionToSpaceMapper* _card_counts_mapper; + + FreeRegionList _free_list; ++ FreeRegionList _uncommit_list; ++ bool _uncommit_list_filled; + + // Each bit in this bitmap indicates that the corresponding region is available + // for allocation. +@@ -123,17 +126,23 @@ class HeapRegionManager: public CHeapObj { + public: + bool is_free(HeapRegion* hr) const; + #endif +- // Returns whether the given region is available for allocation. +- bool is_available(uint region) const; ++ ++ // Returns whether the given region is not available and can be expanded. ++ bool can_expand(uint region) const; + + public: + // Empty constructor, we'll initialize it with the initialize() method. + HeapRegionManager() : _regions(), _heap_mapper(NULL), _num_committed(0), + _next_bitmap_mapper(NULL), _prev_bitmap_mapper(NULL), _bot_mapper(NULL), + _allocated_heapregions_length(0), _available_map(), +- _free_list("Free list", new MasterFreeRegionListMtSafeChecker()) ++ _free_list("Free list", new MasterFreeRegionListMtSafeChecker()), ++ _uncommit_list("Uncommit list", NULL) + { } + ++ // Returns whether the given region is available for allocation. ++ // !is_available is not allowed ++ bool is_available(uint region) const; ++ + void initialize(G1RegionToSpaceMapper* heap_storage, + G1RegionToSpaceMapper* prev_bitmap, + G1RegionToSpaceMapper* next_bitmap, +@@ -141,6 +150,9 @@ public: + G1RegionToSpaceMapper* cardtable, + G1RegionToSpaceMapper* card_counts); + ++ uint extract_uncommit_list(); ++ void free_uncommit_list_memory(); ++ + // Return the "dummy" region used for G1AllocRegion. This is currently a hardwired + // new HeapRegion that owns HeapRegion at index 0. Since at the moment we commit + // the heap from the lowest address, this region (and its associated data +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +index 213380e7..09d12fd3 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp +@@ -109,10 +109,11 @@ void FreeRegionList::fill_in_ext_msg_extra(hrs_ext_msg* msg) { + msg->append(" hd: " PTR_FORMAT " tl: " PTR_FORMAT, _head, _tail); + } + +-void FreeRegionList::remove_all() { ++void FreeRegionList::remove_all(bool uncommit) { + check_mt_safety(); + verify_optional(); + ++ G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* curr = _head; + while (curr != NULL) { + verify_region(curr); +@@ -121,6 +122,11 @@ void FreeRegionList::remove_all() { + curr->set_next(NULL); + curr->set_prev(NULL); + curr->set_containing_set(NULL); ++ if (uncommit) { ++ g1h->_hrm.uncommit_regions(curr->hrm_index(), 1); ++ OrderAccess::storestore(); ++ curr->set_uncommit_list(false); ++ } + curr = next; + } + clear(); +@@ -328,6 +334,48 @@ void FreeRegionList::verify_list() { + name(), total_capacity_bytes(), capacity)); + } + ++uint FreeRegionList::move_regions_to(FreeRegionList* dest, uint num_regions) { ++ check_mt_safety(); ++ assert(num_regions >= 1, hrs_ext_msg(this, "pre-condition")); ++ assert(num_regions < length(), hrs_ext_msg(this, "pre-condition")); ++ assert(dest != NULL && dest->is_empty(), hrs_ext_msg(dest, "pre-condition")); ++ ++ verify_optional(); ++ DEBUG_ONLY(uint old_length = length();) ++ HeapRegion* curr = _tail; ++ uint count = 0; ++ size_t capacity = 0; ++ ++ while (count < num_regions) { ++ if (curr->hrm_index() <= InitialHeapSize / HeapRegion::GrainBytes) { ++ break; ++ } ++ if (_last == curr) { ++ _last = NULL; ++ } ++ curr->set_containing_set(NULL); ++ curr->set_containing_set(dest); ++ curr->set_uncommit_list(true); ++ count++; ++ capacity += curr->capacity(); ++ curr = curr->prev(); ++ assert(curr != NULL, hrs_ext_msg(this, "invariant")); ++ } ++ if (count != 0) { ++ dest->_tail = _tail; ++ dest->_head = curr->next(); ++ dest->_head->set_prev(NULL); ++ dest->_count.increment(count, capacity); ++ dest->verify_optional(); ++ ++ _count.decrement(count, capacity); ++ _tail = curr; ++ _tail->set_next(NULL); ++ verify_optional(); ++ } ++ return count; ++} ++ + // Note on the check_mt_safety() methods below: + // + // Verification of the "master" heap region sets / lists that are +diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp +index 9a9267c4..ede3136d 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp +@@ -249,13 +249,15 @@ public: + void add_ordered(FreeRegionList* from_list); + + // It empties the list by removing all regions from it. +- void remove_all(); ++ void remove_all(bool uncommit = false); + + // Remove all (contiguous) regions from first to first + num_regions -1 from + // this list. + // Num_regions must be > 1. + void remove_starting_at(HeapRegion* first, uint num_regions); + ++ uint move_regions_to(FreeRegionList* dest, uint num_regions); ++ + virtual void verify(); + + virtual void print_on(outputStream* out, bool print_contents = false); +diff --git a/hotspot/src/share/vm/gc_interface/gcCause.cpp b/hotspot/src/share/vm/gc_interface/gcCause.cpp +index bdac7cb0..283df9bf 100644 +--- a/hotspot/src/share/vm/gc_interface/gcCause.cpp ++++ b/hotspot/src/share/vm/gc_interface/gcCause.cpp +@@ -100,6 +100,9 @@ const char* GCCause::to_string(GCCause::Cause cause) { + case _g1_humongous_allocation: + return "G1 Humongous Allocation"; + ++ case _g1_periodic_collection: ++ return "G1 Periodic Collection"; ++ + case _shenandoah_allocation_failure_evac: + return "Allocation Failure During Evacuation"; + +diff --git a/hotspot/src/share/vm/gc_interface/gcCause.hpp b/hotspot/src/share/vm/gc_interface/gcCause.hpp +index 29408d77..5be14548 100644 +--- a/hotspot/src/share/vm/gc_interface/gcCause.hpp ++++ b/hotspot/src/share/vm/gc_interface/gcCause.hpp +@@ -72,6 +72,7 @@ class GCCause : public AllStatic { + + _g1_inc_collection_pause, + _g1_humongous_allocation, ++ _g1_periodic_collection, + + _shenandoah_stop_vm, + _shenandoah_metadata_gc_clear_softrefs, +diff --git a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.hpp b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.hpp +index 9335a9f7..4e8dae21 100644 +--- a/hotspot/src/share/vm/memory/threadLocalAllocBuffer.hpp ++++ b/hotspot/src/share/vm/memory/threadLocalAllocBuffer.hpp +@@ -98,7 +98,7 @@ private: + static GlobalTLABStats* global_stats() { return _global_stats; } + + public: +- ThreadLocalAllocBuffer() : _allocation_fraction(TLABAllocationWeight), _allocated_before_last_gc(0), _initialized(false) { ++ ThreadLocalAllocBuffer() : _allocation_fraction(TLABAllocationWeight), _allocated_before_last_gc(0), _initialized(false), _gclab(false) { + // do nothing. tlabs must be inited by initialize() calls + } + +diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp +index 38cddfed..3a032d04 100644 +--- a/hotspot/src/share/vm/prims/jvm.cpp ++++ b/hotspot/src/share/vm/prims/jvm.cpp +@@ -3286,6 +3286,23 @@ JVM_ENTRY(void, JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio)) + } + JVM_END + ++JVM_ENTRY(void, JVM_AdaptiveHeapSetG1PeriodicGCInterval(JNIEnv *env, jclass klass, jint interval)) ++ JVMWrapper("JVM_AdaptiveHeapSetG1PeriodicGCInterval"); ++ G1PeriodicGCInterval = interval; ++JVM_END ++JVM_ENTRY(jint, JVM_AdaptiveHeapGetG1PeriodicGCInterval(JNIEnv *env, jclass klass)) ++ JVMWrapper("JVM_AdaptiveHeapGetG1PeriodicGCInterval"); ++ return G1PeriodicGCInterval; ++JVM_END ++ ++JVM_ENTRY(void, JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz, jint loadThreshold)) ++ JVMWrapper("JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold"); ++ G1PeriodicGCLoadThreshold = loadThreshold; ++JVM_END ++JVM_ENTRY(jint, JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz)) ++ JVMWrapper("JVM_AdaptiveHeapgetG1PeriodicGCLoadThreshold"); ++ return G1PeriodicGCLoadThreshold; ++JVM_END + + JVM_ENTRY(void, JVM_Yield(JNIEnv *env, jclass threadClass)) + JVMWrapper("JVM_Yield"); +diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h +index 198c52dc..0c0d44a0 100644 +--- a/hotspot/src/share/vm/prims/jvm.h ++++ b/hotspot/src/share/vm/prims/jvm.h +@@ -1586,6 +1586,20 @@ JVM_GetResourceLookupCacheURLs(JNIEnv *env, jobject loader); + JNIEXPORT jintArray JNICALL + JVM_GetResourceLookupCache(JNIEnv *env, jobject loader, const char *resource_name); + ++/* ++ *com.huawei.management.AdaptiveHeapMXBeanImpl ++ */ ++JNIEXPORT void JNICALL ++JVM_AdaptiveHeapSetG1PeriodicGCInterval(JNIEnv *env, jclass klass, jint interval); ++JNIEXPORT jint JNICALL ++JVM_AdaptiveHeapGetG1PeriodicGCInterval(JNIEnv *env, jclass klass); ++ ++ ++JNIEXPORT void JNICALL ++JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz, jint loadThreshold); ++JNIEXPORT jint JNICALL ++JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz); ++ + + /* ========================================================================= + * The following defines a private JVM interface that the JDK can query +diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp +index ab3148e3..cff2e9c3 100644 +--- a/hotspot/src/share/vm/runtime/os.hpp ++++ b/hotspot/src/share/vm/runtime/os.hpp +@@ -823,6 +823,9 @@ class os: AllStatic { + // System loadavg support. Returns -1 if load average cannot be obtained. + static int loadavg(double loadavg[], int nelem); + ++ // Process loadavg support. Returns -1 if load average cannot be obtained. ++ static double get_process_load(); ++ + // Hook for os specific jvm options that we don't want to abort on seeing + static bool obsolete_option(const JavaVMOption *option); + +diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp +index d0185280..710f8cbc 100644 +--- a/hotspot/src/share/vm/runtime/thread.cpp ++++ b/hotspot/src/share/vm/runtime/thread.cpp +@@ -99,6 +99,7 @@ + #include "gc_implementation/shenandoah/shenandoahControlThread.hpp" + #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" + #include "gc_implementation/g1/concurrentMarkThread.inline.hpp" ++#include "gc_implementation/g1/g1CollectedHeap.hpp" + #include "gc_implementation/parallelScavenge/pcTasks.hpp" + #endif // INCLUDE_ALL_GCS + #ifdef COMPILER1 +@@ -3690,6 +3691,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { + ShenandoahControlThread::makeSurrogateLockerThread(THREAD); + } else { + ConcurrentMarkThread::makeSurrogateLockerThread(THREAD); ++ G1CollectedHeap::heap()->init_periodic_gc_thread(); + } + if (HAS_PENDING_EXCEPTION) { + vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); +diff --git a/jdk/make/CreateJars.gmk b/jdk/make/CreateJars.gmk +index 6e484369..559a62b6 100644 +--- a/jdk/make/CreateJars.gmk ++++ b/jdk/make/CreateJars.gmk +@@ -555,7 +555,9 @@ EXCLUDE_PROPWARN_PKGS = com.sun.java.swing.plaf.windows \ + # with a new module system (being discussed for JDK 8). + # + EXPORTED_PRIVATE_PKGS = com.oracle.net \ +- com.oracle.nio ++ com.oracle.nio \ ++ com.huawei.management \ ++ com.huawei.jvm.gc + + $(IMAGES_OUTPUTDIR)/symbols/_the.symbols: $(IMAGES_OUTPUTDIR)/lib/rt.jar + $(RM) -r $(IMAGES_OUTPUTDIR)/symbols/META-INF/sym +diff --git a/jdk/make/data/classlist/classlist.linux b/jdk/make/data/classlist/classlist.linux +index 2a3915c0..737aefe2 100644 +--- a/jdk/make/data/classlist/classlist.linux ++++ b/jdk/make/data/classlist/classlist.linux +@@ -2556,4 +2556,5 @@ javax/swing/plaf/basic/BasicToolBarSeparatorUI + java/awt/event/AdjustmentEvent + java/awt/MenuBar + sun/awt/X11/XErrorEvent ++com/huawei/jvm/gc + # eea35d9d56e0006e +diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk +index d374a47a..2a155ea1 100644 +--- a/jdk/make/lib/CoreLibraries.gmk ++++ b/jdk/make/lib/CoreLibraries.gmk +@@ -143,6 +143,7 @@ LIBJAVA_SRC_DIRS += $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/l + $(JDK_TOPDIR)/src/share/native/common \ + $(JDK_TOPDIR)/src/share/native/sun/misc \ + $(JDK_TOPDIR)/src/share/native/sun/reflect \ ++ $(JDK_TOPDIR)/src/share/native/com/huawei/jvm/gc \ + $(JDK_TOPDIR)/src/share/native/java/util \ + $(JDK_TOPDIR)/src/share/native/java/util/concurrent/atomic \ + $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/common \ +diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers +index d686924a..7aeab583 100644 +--- a/jdk/make/mapfiles/libjava/mapfile-vers ++++ b/jdk/make/mapfiles/libjava/mapfile-vers +@@ -215,6 +215,7 @@ SUNWprivate_1.1 { + Java_java_lang_System_setErr0; + Java_java_lang_System_setIn0; + Java_java_lang_System_setOut0; ++ Java_com_huawei_jvm_gc_AdaptiveHeapMXBeanImpl_registerNatives; + Java_java_lang_Thread_registerNatives; + Java_java_lang_Throwable_fillInStackTrace; + Java_java_lang_Throwable_getStackTraceDepth; +diff --git a/jdk/make/mapfiles/libjava/reorder-sparc b/jdk/make/mapfiles/libjava/reorder-sparc +index 96f8e735..95793a5b 100644 +--- a/jdk/make/mapfiles/libjava/reorder-sparc ++++ b/jdk/make/mapfiles/libjava/reorder-sparc +@@ -104,3 +104,4 @@ text: .text%Java_java_util_TimeZone_getSystemTimeZoneID; + text: .text%findJavaTZ_md; + text: .text%Java_java_lang_StrictMath_log; + text: .text%Java_java_lang_StrictMath_sqrt; ++text: .text%Java_com_huawei_jvm_gc_AdaptiveHeapMXBeanImpl_registerNatives; +diff --git a/jdk/make/mapfiles/libjava/reorder-x86 b/jdk/make/mapfiles/libjava/reorder-x86 +index e0566b32..5b7a7ee1 100644 +--- a/jdk/make/mapfiles/libjava/reorder-x86 ++++ b/jdk/make/mapfiles/libjava/reorder-x86 +@@ -10,6 +10,7 @@ text: .text%collapse: OUTPUTDIR/canonicalize_md.o; + text: .text%Java_java_lang_Object_registerNatives; + text: .text%Java_java_lang_System_registerNatives; + text: .text%Java_java_lang_Thread_registerNatives; ++text: .text%Java_com_huawei_jvm_gc_AdaptiveHeapMXBeanImpl_registerNatives; + text: .text%Java_java_security_AccessController_getStackAccessControlContext; + text: .text%Java_java_security_AccessController_getInheritedAccessControlContext; + text: .text%Java_java_lang_ClassLoader_registerNatives; +diff --git a/jdk/src/share/classes/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.java b/jdk/src/share/classes/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.java +new file mode 100644 +index 00000000..1443fb04 +--- /dev/null ++++ b/jdk/src/share/classes/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.java +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (c) 2020, Huawei Technologies Co., LTD. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package com.huawei.jvm.gc; ++import com.huawei.management.AdaptiveHeapMXBean; ++import sun.management.Util; ++import javax.management.ObjectName; ++ ++public class AdaptiveHeapMXBeanImpl implements AdaptiveHeapMXBean { ++ private static native void registerNatives(); ++ ++ static { ++ registerNatives(); ++ } ++ ++ private final static String ADAPTIVE_HEAP_MXBEAN_NAME = "com.huawei.management:type=AdaptiveHeap"; ++ @Override ++ public void setG1PeriodicGCInterval(int interval) { ++ setG1PeriodicGCIntervalImpl(interval); ++ } ++ @Override ++ public void setG1PeriodicGCLoadThreshold(int loadThreshold) { ++ setG1PeriodicGCLoadThresholdImpl(loadThreshold); ++ } ++ @Override ++ public int getG1PeriodicGCInterval() { ++ return getG1PeriodicGCIntervalImpl(); ++ } ++ @Override ++ public int getG1PeriodicGCLoadThreshold() { ++ return getG1PeriodicGCLoadThresholdImpl(); ++ } ++ @Override ++ public ObjectName getObjectName() { ++ return Util.newObjectName(ADAPTIVE_HEAP_MXBEAN_NAME); ++ } ++ ++ ++ private static native void setG1PeriodicGCIntervalImpl(int interval); ++ private static native void setG1PeriodicGCLoadThresholdImpl(int loadThreshold); ++ private static native int getG1PeriodicGCIntervalImpl(); ++ private static native int getG1PeriodicGCLoadThresholdImpl(); ++} +diff --git a/jdk/src/share/classes/com/huawei/management/AdaptiveHeapMXBean.java b/jdk/src/share/classes/com/huawei/management/AdaptiveHeapMXBean.java +new file mode 100644 +index 00000000..70563b58 +--- /dev/null ++++ b/jdk/src/share/classes/com/huawei/management/AdaptiveHeapMXBean.java +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 2020, Huawei Technologies Co., LTD. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package com.huawei.management; ++ ++import java.lang.management.PlatformManagedObject; ++import java.util.List; ++public interface AdaptiveHeapMXBean extends PlatformManagedObject { ++ void setG1PeriodicGCInterval(int interval); ++ void setG1PeriodicGCLoadThreshold(int loadThreshold); ++ int getG1PeriodicGCInterval(); ++ int getG1PeriodicGCLoadThreshold(); ++} +diff --git a/jdk/src/share/classes/java/lang/management/PlatformComponent.java b/jdk/src/share/classes/java/lang/management/PlatformComponent.java +index 0c67543e..afc48d24 100644 +--- a/jdk/src/share/classes/java/lang/management/PlatformComponent.java ++++ b/jdk/src/share/classes/java/lang/management/PlatformComponent.java +@@ -37,6 +37,7 @@ import javax.management.ObjectName; + + import com.sun.management.HotSpotDiagnosticMXBean; + import com.sun.management.UnixOperatingSystemMXBean; ++import com.huawei.management.AdaptiveHeapMXBean; + + import sun.management.ManagementFactoryHelper; + import sun.management.Util; +@@ -270,9 +271,20 @@ enum PlatformComponent { + public List getMXBeans() { + return Collections.singletonList(ManagementFactoryHelper.getDiagnosticMXBean()); + } ++ }), ++ /** ++ * ADAPTIVE Heap. ++ */ ++ ADAPTIVE_HEAP( ++ "com.huawei.management.AdaptiveHeapMXBean", ++ "com.huawei.management", "AdaptiveHeap", defaultKeyProperties(), ++ true, ++ new MXBeanFetcher() { ++ public List getMXBeans() { ++ return Collections.singletonList(ManagementFactoryHelper.getAdaptiveHeapMXBean()); ++ } + }); + +- + /** + * A task that returns the MXBeans for a component. + */ +diff --git a/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java b/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java +index be82ddae..d5df523e 100644 +--- a/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java ++++ b/jdk/src/share/classes/sun/management/ManagementFactoryHelper.java +@@ -48,6 +48,9 @@ import java.util.List; + import com.sun.management.DiagnosticCommandMBean; + import com.sun.management.HotSpotDiagnosticMXBean; + ++import com.huawei.management.AdaptiveHeapMXBean; ++import com.huawei.jvm.gc.AdaptiveHeapMXBeanImpl; ++ + import static java.lang.management.ManagementFactory.*; + + /** +@@ -65,6 +68,7 @@ public class ManagementFactoryHelper { + private static RuntimeImpl runtimeMBean = null; + private static CompilationImpl compileMBean = null; + private static OperatingSystemImpl osMBean = null; ++ private static AdaptiveHeapMXBeanImpl adaptiveHeapMXBean = null; + + public static synchronized ClassLoadingMXBean getClassLoadingMXBean() { + if (classMBean == null) { +@@ -108,6 +112,13 @@ public class ManagementFactoryHelper { + return osMBean; + } + ++ public static synchronized AdaptiveHeapMXBean getAdaptiveHeapMXBean() { ++ if (adaptiveHeapMXBean == null) { ++ adaptiveHeapMXBean = new AdaptiveHeapMXBeanImpl(); ++ } ++ return adaptiveHeapMXBean; ++ } ++ + public static List getMemoryPoolMXBeans() { + MemoryPoolMXBean[] pools = MemoryImpl.getMemoryPools(); + List list = new ArrayList<>(pools.length); +diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h +index 6e64cb0d..9eafbbb8 100644 +--- a/jdk/src/share/javavm/export/jvm.h ++++ b/jdk/src/share/javavm/export/jvm.h +@@ -1430,6 +1430,21 @@ JNIEXPORT jintArray JNICALL + JVM_GetResourceLookupCache(JNIEnv *env, jobject loader, const char *resource_name); + + ++/* ++ *com.huawei.management.AdaptiveHeapMXBeanImpl ++ */ ++JNIEXPORT void JNICALL ++JVM_AdaptiveHeapSetG1PeriodicGCInterval(JNIEnv *env, jclass klass, jint interval); ++JNIEXPORT jint JNICALL ++JVM_AdaptiveHeapGetG1PeriodicGCInterval(JNIEnv *env, jclass klass); ++ ++ ++JNIEXPORT void JNICALL ++JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz, jint loadThreshold); ++JNIEXPORT jint JNICALL ++JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold(JNIEnv *env, jclass clazz); ++ ++ + /* ========================================================================= + * The following defines a private JVM interface that the JDK can query + * for the JVM version and capabilities. sun.misc.Version defines +diff --git a/jdk/src/share/native/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c b/jdk/src/share/native/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c +new file mode 100644 +index 00000000..1f75e7cb +--- /dev/null ++++ b/jdk/src/share/native/com/huawei/jvm/gc/AdaptiveHeapMXBeanImpl.c +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2020, Huawei Technologies Co., LTD. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. Alibaba designates this ++ * particular file as subject to the "Classpath" exception as provided ++ * by Oracle in the LICENSE file that accompanied this code. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "jni.h" ++#include "jvm.h" ++#include "com_huawei_jvm_gc_AdaptiveHeapMXBeanImpl.h" ++ ++#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0])) ++ ++static JNINativeMethod methods[] = { ++ {"setG1PeriodicGCIntervalImpl", "(I)V", (void *)&JVM_AdaptiveHeapSetG1PeriodicGCInterval}, ++ {"getG1PeriodicGCIntervalImpl", "()I", (void *)&JVM_AdaptiveHeapGetG1PeriodicGCInterval}, ++ {"setG1PeriodicGCLoadThresholdImpl", "(I)V", (void *)&JVM_AdaptiveHeapSetG1PeriodicGCLoadThreshold}, ++ {"getG1PeriodicGCLoadThresholdImpl", "()I", (void *)&JVM_AdaptiveHeapGetG1PeriodicGCLoadThreshold}, ++ ++}; ++ ++JNIEXPORT void JNICALL ++Java_com_huawei_jvm_gc_AdaptiveHeapMXBeanImpl_registerNatives(JNIEnv *env, jclass cls) ++{ ++ (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); ++} +diff --git a/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c b/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c +index a2ddcb93..93af600d 100644 +--- a/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c ++++ b/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c +@@ -57,7 +57,7 @@ static struct perfbuf { + ticks *cpus; + } counters; + +-#define DEC_64 "%lld" ++#define DEC_64 "%lud" + + static void next_line(FILE *f) { + while (fgetc(f) != '\n'); diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index 4659dca..422650f 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 8 +Release: 9 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1064,6 +1064,7 @@ Patch135: 8223940-Private-key-not-supported-by-chosen-signature.patch Patch136: 8236512-PKCS11-Connection-closed-after-Cipher.doFinal-and-NoPadding.patch Patch137: 8250861-Crash-in-MinINode-Ideal-PhaseGVN-bool.patch Patch138: add-appcds-file-lock.patch +Patch139: G1-memory-uncommit.patch ############################################# # @@ -1483,6 +1484,7 @@ pushd %{top_level_dir_name} %patch136 -p1 %patch137 -p1 %patch138 -p1 +%patch139 -p1 popd @@ -2099,6 +2101,9 @@ require "copy_jdk_configs.lua" %endif %changelog +* Thu Dec 22 2020 cruise01 - 1:1.8.0.272-b10.9 +- add G1-memory-uncommit.patch + * Thu Dec 22 2020 kuenking - 1:1.8.0.272-b10.8 - add add-appcds-file-lock.patch -- Gitee From 2920200fcb29766e05a128310bcb00b0ed653fcb Mon Sep 17 00:00:00 2001 From: miaozhuojun Date: Tue, 22 Dec 2020 20:46:09 +0800 Subject: [PATCH 3/7] I2AGIU: add 8015927-Class-reference-duplicates-in-constant-pool.patch --- ...eference-duplicates-in-constant-pool.patch | 115 ++++++++++++++++++ java-1.8.0-openjdk.spec | 7 +- 2 files changed, 121 insertions(+), 1 deletion(-) create mode 100755 8015927-Class-reference-duplicates-in-constant-pool.patch diff --git a/8015927-Class-reference-duplicates-in-constant-pool.patch b/8015927-Class-reference-duplicates-in-constant-pool.patch new file mode 100755 index 0000000..81fe524 --- /dev/null +++ b/8015927-Class-reference-duplicates-in-constant-pool.patch @@ -0,0 +1,115 @@ +diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +index eecd6807..11b24341 100644 +--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java ++++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +@@ -461,11 +461,11 @@ public class ClassWriter extends ClassFile { + poolbuf.appendChar(pool.put(names.fromString((String)value))); + } else if (value instanceof UniqueType) { + Type type = ((UniqueType)value).type; +- if (type instanceof MethodType) { ++ if (type.hasTag(METHOD)) { + poolbuf.appendByte(CONSTANT_MethodType); + poolbuf.appendChar(pool.put(typeSig((MethodType)type))); + } else { +- if (type.hasTag(CLASS)) enterInner((ClassSymbol)type.tsym); ++ Assert.check(type.hasTag(ARRAY)); + poolbuf.appendByte(CONSTANT_Class); + poolbuf.appendChar(pool.put(xClassName(type))); + } +diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java +index 4389d08b..f87c1053 100644 +--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java ++++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java +@@ -28,6 +28,7 @@ package com.sun.tools.javac.jvm; + import com.sun.tools.javac.code.Kinds; + import com.sun.tools.javac.code.Symbol; + import com.sun.tools.javac.code.Symbol.*; ++import com.sun.tools.javac.code.TypeTag; + import com.sun.tools.javac.code.Type; + import com.sun.tools.javac.code.Types; + import com.sun.tools.javac.code.Types.UniqueType; +@@ -126,7 +127,14 @@ public class Pool { + } else if (o instanceof VarSymbol) { + return new Variable((VarSymbol)o, types); + } else if (o instanceof Type) { +- return new UniqueType((Type)o, types); ++ Type t = (Type)o; ++ // ClassRefs can come from ClassSymbols or from Types. ++ // Return the symbol for these types to avoid duplicates ++ // in the constant pool ++ if (t.hasTag(TypeTag.CLASS)) ++ return t.tsym; ++ else ++ return new UniqueType(t, types); + } else { + return o; + } +diff --git a/langtools/test/tools/javac/jvm/ClassRefDupInConstantPoolTest.java b/langtools/test/tools/javac/jvm/ClassRefDupInConstantPoolTest.java +new file mode 100644 +index 00000000..98c7cf8d +--- /dev/null ++++ b/langtools/test/tools/javac/jvm/ClassRefDupInConstantPoolTest.java +@@ -0,0 +1,63 @@ ++/* ++ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++/* ++ * @test ++ * @bug 8015927 ++ * @summary Class reference duplicates in constant pool ++ * @clean ClassRefDupInConstantPoolTest$Duplicates.class ++ * @run main ClassRefDupInConstantPoolTest ++ */ ++ ++import java.util.TreeSet; ++ ++import com.sun.tools.classfile.*; ++import com.sun.tools.classfile.ConstantPool.*; ++ ++public class ClassRefDupInConstantPoolTest { ++ public static void main(String[] args) throws Exception { ++ ClassFile cls = ClassFile.read(ClassRefDupInConstantPoolTest.class. ++ getResourceAsStream("ClassRefDupInConstantPoolTest$Duplicates.class")); ++ ConstantPool pool = cls.constant_pool; ++ ++ int duplicates = 0; ++ TreeSet set = new TreeSet<>(); ++ for (CPInfo i : pool.entries()) { ++ if (i.getTag() == ConstantPool.CONSTANT_Class) { ++ CONSTANT_Class_info ci = (CONSTANT_Class_info)i; ++ if (!set.add(ci.name_index)) { ++ duplicates++; ++ System.out.println("DUPLICATE CLASS REF " + ci.getName()); ++ } ++ } ++ } ++ if (duplicates > 0) ++ throw new Exception("Test Failed"); ++ } ++ ++ class Duplicates { ++ String concat(String s1, String s2) { ++ return s1 + (s2 == s1 ? " " : s2); ++ } ++ } ++} diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index 422650f..6c62a2c 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 9 +Release: 10 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1065,6 +1065,7 @@ Patch136: 8236512-PKCS11-Connection-closed-after-Cipher.doFinal-and-NoPadding.pa Patch137: 8250861-Crash-in-MinINode-Ideal-PhaseGVN-bool.patch Patch138: add-appcds-file-lock.patch Patch139: G1-memory-uncommit.patch +Patch140: 8015927-Class-reference-duplicates-in-constant-pool.patch ############################################# # @@ -1485,6 +1486,7 @@ pushd %{top_level_dir_name} %patch137 -p1 %patch138 -p1 %patch139 -p1 +%patch140 -p1 popd @@ -2101,6 +2103,9 @@ require "copy_jdk_configs.lua" %endif %changelog +* Thu Dec 22 2020 miaozhuojun - 1:1.8.0.272-b10.10 +- add 8015927-Class-reference-duplicates-in-constant-pool.patch + * Thu Dec 22 2020 cruise01 - 1:1.8.0.272-b10.9 - add G1-memory-uncommit.patch -- Gitee From 9244b456f57b59a64c566ea7fb1ae412d07f6b24 Mon Sep 17 00:00:00 2001 From: DataAndOperation Date: Wed, 23 Dec 2020 10:07:34 +0800 Subject: [PATCH 4/7] I2AHH2: add 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch --- ...n-up-type-annotation-exception-index.patch | 91 +++++++++++++++++++ java-1.8.0-openjdk.spec | 7 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100755 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch diff --git a/8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch b/8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch new file mode 100755 index 0000000..2c99dc4 --- /dev/null +++ b/8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch @@ -0,0 +1,91 @@ +diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java +index c481ea5d..f1f92b6a 100644 +--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java ++++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java +@@ -297,6 +297,29 @@ public class TypeAnnotationPosition { + isValidOffset = true; + } + ++ public boolean hasCatchType() { ++ return exception_index < 0 && exception_index != Integer.MIN_VALUE; ++ } ++ ++ public int getCatchType() { ++ Assert.check(hasCatchType(), ++ "exception_index does not contain valid catch info"); ++ return ((-this.exception_index) - 1) & 0xff ; ++ } ++ ++ public int getStartPos() { ++ Assert.check(hasCatchType(), ++ "exception_index does not contain valid catch info"); ++ return ((-this.exception_index) - 1) >> 8; ++ } ++ ++ public void setCatchInfo(final int catchType, final int startPos) { ++ Assert.check(this.exception_index < 0, ++ "exception_index already contains a bytecode index"); ++ Assert.check(catchType >= 0, "Expected a valid catch type"); ++ this.exception_index = -((catchType | startPos << 8) + 1); ++ } ++ + /** + * Decode the binary representation for a type path and set + * the {@code location} field. +diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java +index 738c5a1d..622a5942 100644 +--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java ++++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java +@@ -2135,14 +2135,16 @@ public class Code { + // same location; updating one is enough. + // Use -666 as a marker that the exception_index was already updated. + if (p.type_index != -666) { +- p.exception_index = findExceptionIndex(p.type_index); ++ p.exception_index = findExceptionIndex(p); + p.type_index = -666; + } + } + } + } + +- private int findExceptionIndex(int catchType) { ++ private int findExceptionIndex(TypeAnnotationPosition p) { ++ final int catchType = p.getCatchType(); ++ final int startPos = p.getStartPos(); + if (catchType == Integer.MIN_VALUE) { + // We didn't set the catch type index correctly. + // This shouldn't happen. +@@ -2154,8 +2156,9 @@ public class Code { + for (int i = 0; i < len; ++i) { + char[] catchEntry = iter.head; + iter = iter.tail; +- char ct = catchEntry[3]; +- if (catchType == ct) { ++ int ct = catchEntry[3]; ++ int sp = catchEntry[0]; ++ if (catchType == ct && sp == startPos) { + return i; + } + } +diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java +index 4cc7fb7b..f79d3eee 100644 +--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java ++++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java +@@ -1609,7 +1609,7 @@ public class Gen extends JCTree.Visitor { + if (subCatch.type.isAnnotated()) { + for (Attribute.TypeCompound tc : + subCatch.type.getAnnotationMirrors()) { +- tc.position.type_index = catchType; ++ tc.position.setCatchInfo(catchType, startpc); + } + } + } +@@ -1626,7 +1626,7 @@ public class Gen extends JCTree.Visitor { + if (subCatch.type.isAnnotated()) { + for (Attribute.TypeCompound tc : + subCatch.type.getAnnotationMirrors()) { +- tc.position.type_index = catchType; ++ tc.position.setCatchInfo(catchType, startpc); + } + } + } diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index 6c62a2c..c75736f 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 10 +Release: 11 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1066,6 +1066,7 @@ Patch137: 8250861-Crash-in-MinINode-Ideal-PhaseGVN-bool.patch Patch138: add-appcds-file-lock.patch Patch139: G1-memory-uncommit.patch Patch140: 8015927-Class-reference-duplicates-in-constant-pool.patch +Patch141: 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch ############################################# # @@ -1487,6 +1488,7 @@ pushd %{top_level_dir_name} %patch138 -p1 %patch139 -p1 %patch140 -p1 +%patch141 -p1 popd @@ -2103,6 +2105,9 @@ require "copy_jdk_configs.lua" %endif %changelog +* Wed Dec 23 2020 DataAndOperation - 1:1.8.0.272-b10.11 +- add 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch + * Thu Dec 22 2020 miaozhuojun - 1:1.8.0.272-b10.10 - add 8015927-Class-reference-duplicates-in-constant-pool.patch -- Gitee From 74c4669b94acd86bed9bc7f57e46ee45c3e447cd Mon Sep 17 00:00:00 2001 From: wujiahua Date: Wed, 23 Dec 2020 14:39:47 +0800 Subject: [PATCH 5/7] I2AJEI: add 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch --- ...eturn-null-if-the-args-list-is-empty.patch | 165 ++++++++++++++++++ java-1.8.0-openjdk.spec | 7 +- 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100755 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch diff --git a/8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch b/8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch new file mode 100755 index 0000000..9351b43 --- /dev/null +++ b/8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch @@ -0,0 +1,165 @@ +diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java +index 40248923..637d83b2 100644 +--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java ++++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java +@@ -2051,6 +2051,9 @@ public class ClassReader { + } + + private List adjustMethodParams(long flags, List args) { ++ if (args.isEmpty()) { ++ return args; ++ } + boolean isVarargs = (flags & VARARGS) != 0; + if (isVarargs) { + Type varargsElem = args.last(); +diff --git a/langtools/test/tools/javac/AvoidNPEAtClassReader/AvoidNPEAtClassReaderTest.java b/langtools/test/tools/javac/AvoidNPEAtClassReader/AvoidNPEAtClassReaderTest.java +new file mode 100644 +index 00000000..3b47d694 +--- /dev/null ++++ b/langtools/test/tools/javac/AvoidNPEAtClassReader/AvoidNPEAtClassReaderTest.java +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++/** ++ * @test ++ * @bug 8207160 ++ * @summary ClassReader::adjustMethodParams can potentially return null if the args list is empty ++ * @compile pkg/Outer.jasm pkg/Outer$Inner.jasm AvoidNPEAtClassReaderTest.java ++ */ ++ ++ ++/** this test is checking that javac doesn't fail with NPE when reading inner classes with constructors ++ * that doesn't have as a parameter a reference to the outer class. Such constructors were generated by ++ * versions of javac previous to JDK7. ++ */ ++ ++import pkg.*; ++ ++public class AvoidNPEAtClassReaderTest { ++ public void bar(Outer outer) { ++ Object stuff = outer.foo(); ++ } ++} +diff --git a/langtools/test/tools/javac/AvoidNPEAtClassReader/pkg/Outer$Inner.jasm b/langtools/test/tools/javac/AvoidNPEAtClassReader/pkg/Outer$Inner.jasm +new file mode 100644 +index 00000000..d3ee1331 +--- /dev/null ++++ b/langtools/test/tools/javac/AvoidNPEAtClassReader/pkg/Outer$Inner.jasm +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package pkg; ++ ++super public final class Outer$Inner ++ version 52:0 ++{ ++ ++final synthetic Field this$0:"Lpkg/Outer;"; ++ ++public Method "":"()V" ++ stack 1 locals 1 ++{ ++ aload_0; ++ invokespecial Method java/lang/Object."":"()V"; ++ return; ++} ++ ++public final InnerClass Inner=class Outer$Inner of class Outer; ++ ++} // end Class Outer$Inner +diff --git a/langtools/test/tools/javac/AvoidNPEAtClassReader/pkg/Outer.jasm b/langtools/test/tools/javac/AvoidNPEAtClassReader/pkg/Outer.jasm +new file mode 100644 +index 00000000..29239b13 +--- /dev/null ++++ b/langtools/test/tools/javac/AvoidNPEAtClassReader/pkg/Outer.jasm +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package pkg; ++ ++super public class Outer ++ version 52:0 ++{ ++ ++ ++public Method "":"()V" ++ stack 1 locals 1 ++{ ++ aload_0; ++ invokespecial Method java/lang/Object."":"()V"; ++ return; ++} ++ ++public Method foo:"()Lpkg/Outer$Inner;" ++ stack 1 locals 1 ++{ ++ aconst_null; ++ areturn; ++} ++ ++public final InnerClass Inner=class Outer$Inner of class Outer; ++ ++} // end Class Outer diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index c75736f..7339448 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 11 +Release: 12 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1067,6 +1067,7 @@ Patch138: add-appcds-file-lock.patch Patch139: G1-memory-uncommit.patch Patch140: 8015927-Class-reference-duplicates-in-constant-pool.patch Patch141: 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch +Patch142: 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch ############################################# # @@ -1489,6 +1490,7 @@ pushd %{top_level_dir_name} %patch139 -p1 %patch140 -p1 %patch141 -p1 +%patch142 -p1 popd @@ -2105,6 +2107,9 @@ require "copy_jdk_configs.lua" %endif %changelog +* Wed Dec 23 2020 wujiahua - 1:1.8.0.272-b10.12 +- add 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch + * Wed Dec 23 2020 DataAndOperation - 1:1.8.0.272-b10.11 - add 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch -- Gitee From 11b6dce84ff6fad40c9c20a7d80e149a71d1aa14 Mon Sep 17 00:00:00 2001 From: hubodao Date: Wed, 23 Dec 2020 16:55:22 +0800 Subject: [PATCH 6/7] I2AKQH: add delete-untrustworthy-cacert.patch --- delete-untrustworthy-cacert.patch | 217 ++++++++++++++++++++++++++++++ java-1.8.0-openjdk.spec | 7 +- 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100755 delete-untrustworthy-cacert.patch diff --git a/delete-untrustworthy-cacert.patch b/delete-untrustworthy-cacert.patch new file mode 100755 index 0000000..5d811f8 --- /dev/null +++ b/delete-untrustworthy-cacert.patch @@ -0,0 +1,217 @@ +diff --git a/jdk/make/data/cacerts/addtrustexternalca b/jdk/make/data/cacerts/addtrustexternalca +deleted file mode 100644 +index ad84cad9..00000000 +--- a/jdk/make/data/cacerts/addtrustexternalca ++++ /dev/null +@@ -1,32 +0,0 @@ +-Owner: CN=AddTrust External CA Root, OU=AddTrust External TTP Network, O=AddTrust AB, C=SE +-Issuer: CN=AddTrust External CA Root, OU=AddTrust External TTP Network, O=AddTrust AB, C=SE +-Serial number: 1 +-Valid from: Tue May 30 10:48:38 GMT 2000 until: Sat May 30 10:48:38 GMT 2020 +-Signature algorithm name: SHA1withRSA +-Subject Public Key Algorithm: 2048-bit RSA key +-Version: 3 +------BEGIN CERTIFICATE----- +-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +-MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +-IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +-MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +-FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +-bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +-H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +-uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +-mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +-a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +-E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +-WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +-VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +-Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +-IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +-AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +-YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +-6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +-Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +-c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +-mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +------END CERTIFICATE----- +diff --git a/jdk/make/data/cacerts/addtrustqualifiedca b/jdk/make/data/cacerts/addtrustqualifiedca +deleted file mode 100644 +index 0c62d44c..00000000 +--- a/jdk/make/data/cacerts/addtrustqualifiedca ++++ /dev/null +@@ -1,32 +0,0 @@ +-Owner: CN=AddTrust Qualified CA Root, OU=AddTrust TTP Network, O=AddTrust AB, C=SE +-Issuer: CN=AddTrust Qualified CA Root, OU=AddTrust TTP Network, O=AddTrust AB, C=SE +-Serial number: 1 +-Valid from: Tue May 30 10:44:50 GMT 2000 until: Sat May 30 10:44:50 GMT 2020 +-Signature algorithm name: SHA1withRSA +-Subject Public Key Algorithm: 2048-bit RSA key +-Version: 3 +------BEGIN CERTIFICATE----- +-MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU +-MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +-b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 +-MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK +-EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh +-BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B +-AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq +-xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G +-87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i +-2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U +-WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 +-0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G +-A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T +-AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr +-pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL +-ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm +-aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv +-hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm +-hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +-dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 +-P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y +-iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no +-xqE= +------END CERTIFICATE----- +diff --git a/jdk/make/data/cacerts/thawtepremiumserverca b/jdk/make/data/cacerts/thawtepremiumserverca +deleted file mode 100644 +index 2df456ab..00000000 +--- a/jdk/make/data/cacerts/thawtepremiumserverca ++++ /dev/null +@@ -1,27 +0,0 @@ +-Owner: EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA +-Issuer: EMAILADDRESS=premium-server@thawte.com, CN=Thawte Premium Server CA, OU=Certification Services Division, O=Thawte Consulting cc, L=Cape Town, ST=Western Cape, C=ZA +-Serial number: 36122296c5e338a520a1d25f4cd70954 +-Valid from: Thu Aug 01 00:00:00 GMT 1996 until: Fri Jan 01 23:59:59 GMT 2021 +-Signature algorithm name: SHA1withRSA +-Subject Public Key Algorithm: 1024-bit RSA key +-Version: 3 +------BEGIN CERTIFICATE----- +-MIIDNjCCAp+gAwIBAgIQNhIilsXjOKUgodJfTNcJVDANBgkqhkiG9w0BAQUFADCB +-zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ +-Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE +-CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh +-d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl +-cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIxMDEwMTIzNTk1OVow +-gc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcT +-CUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNV +-BAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRo +-YXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1z +-ZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +-aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560 +-ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j +-+ao6hnO2RlNYyIkFvYMRuHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/ +-BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBlkKyID1bZ5jA01CbH0FDxkt5r1DmI +-CSLGpmODA/eZd9iy5Ri4XWPz1HP7bJyZePFLeH0ZJMMrAoT4vCLZiiLXoPxx7JGH +-IPG47LHlVYCsPVLIOQ7C8MAFT9aCdYy9X9LcdpoFEsmvcsPcJX6kTY4XpeCHf+Ga +-WuFg3GQjPEIuTQ== +------END CERTIFICATE----- +diff --git a/jdk/make/data/cacerts/utnuserfirstobjectca b/jdk/make/data/cacerts/utnuserfirstobjectca +deleted file mode 100644 +index 80a0b5c2..00000000 +--- a/jdk/make/data/cacerts/utnuserfirstobjectca ++++ /dev/null +@@ -1,33 +0,0 @@ +-Owner: CN=UTN-USERFirst-Object, OU=http://www.usertrust.com, O=The USERTRUST Network, L=Salt Lake City, ST=UT, C=US +-Issuer: CN=UTN-USERFirst-Object, OU=http://www.usertrust.com, O=The USERTRUST Network, L=Salt Lake City, ST=UT, C=US +-Serial number: 44be0c8b500024b411d3362de0b35f1b +-Valid from: Fri Jul 09 18:31:20 GMT 1999 until: Tue Jul 09 18:40:36 GMT 2019 +-Signature algorithm name: SHA1withRSA +-Subject Public Key Algorithm: 2048-bit RSA key +-Version: 3 +------BEGIN CERTIFICATE----- +-MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB +-lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt +-T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV +-BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc +-BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 +-dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC +-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP +-HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO +-KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo +-5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ +-pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb +-kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC +-AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +-FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov +-L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV +-HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN +-AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw +-NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB +-mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU +-4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 +-81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR +-Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= +------END CERTIFICATE----- +diff --git a/jdk/make/data/cacerts/verisigntsaca b/jdk/make/data/cacerts/verisigntsaca +deleted file mode 100644 +index 9813ddae..00000000 +--- a/jdk/make/data/cacerts/verisigntsaca ++++ /dev/null +@@ -1,24 +0,0 @@ +-Owner: CN=Thawte Timestamping CA, OU=Thawte Certification, O=Thawte, L=Durbanville, ST=Western Cape, C=ZA +-Issuer: CN=Thawte Timestamping CA, OU=Thawte Certification, O=Thawte, L=Durbanville, ST=Western Cape, C=ZA +-Serial number: 67c8e1e8e3be1cbdfc913b8ea6238749 +-Valid from: Wed Jan 01 00:00:00 GMT 1997 until: Fri Jan 01 23:59:59 GMT 2021 +-Signature algorithm name: SHA1withRSA +-Subject Public Key Algorithm: 1024-bit RSA key +-Version: 3 +------BEGIN CERTIFICATE----- +-MIICsDCCAhmgAwIBAgIQZ8jh6OO+HL38kTuOpiOHSTANBgkqhkiG9w0BAQUFADCB +-izELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxML +-RHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENl +-cnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcN +-OTcwMTAxMDAwMDAwWhcNMjEwMTAxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT +-BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNV +-BAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNV +-BAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0A +-MIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u +-6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522 +-FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzAR +-MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAS+mqF4EF+3kKMZ/F +-QfRWVKvpwuWXjhj+kckMPiZkyaFMJ2SnvQGTVXFuF0853BvcSTUQOSP/ypvIz2Y/ +-3Ewa1IEGQlIf4SaxFhe65nByMUToTo1b5NP50OOPJWQx5yr4GIg2GlLFDUE1G2m3 +-JvUXzMEZXkt8XOKDgJH6L/uatxY= +------END CERTIFICATE----- +diff --git a/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java b/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java +index af78073b..6b5f692e 100644 +--- a/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java ++++ b/jdk/test/sun/security/lib/cacerts/VerifyCACerts.java +@@ -57,7 +57,7 @@ public class VerifyCACerts { + // SHA-256 of cacerts, can be generated with + // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 + private static final String CHECKSUM +- = "84:BB:36:9E:B0:07:A7:C5:7F:38:EC:36:82:5C:0F:46:C0:35:3B:B1:1F:06:C2:D0:47:B9:39:FA:87:64:E5:9D"; ++ = "8E:A5:85:3C:66:C0:7C:B1:2A:B6:67:31:B3:4A:8E:78:1B:8D:DC:49:F1:42:65:DB:CE:7C:69:41:F3:94:3A:F7"; + + // map of cert alias to SHA-256 fingerprint + @SuppressWarnings("serial") +@@ -92,12 +92,6 @@ public class VerifyCACerts { + "E7:93:C9:B0:2F:D8:AA:13:E2:1C:31:22:8A:CC:B0:81:19:64:3B:74:9C:89:89:64:B1:74:6D:46:C3:D4:CB:D2"); + put("usertrusteccca [jdk]", + "4F:F4:60:D5:4B:9C:86:DA:BF:BC:FC:57:12:E0:40:0D:2B:ED:3F:BC:4D:4F:BD:AA:86:E0:6A:DC:D2:A9:AD:7A"); +- put("utnuserfirstobjectca [jdk]", +- "6F:FF:78:E4:00:A7:0C:11:01:1C:D8:59:77:C4:59:FB:5A:F9:6A:3D:F0:54:08:20:D0:F4:B8:60:78:75:E5:8F"); +- put("addtrustexternalca [jdk]", +- "68:7F:A4:51:38:22:78:FF:F0:C8:B1:1F:8D:43:D5:76:67:1C:6E:B2:BC:EA:B4:13:FB:83:D9:65:D0:6D:2F:F2"); +- put("addtrustqualifiedca [jdk]", +- "80:95:21:08:05:DB:4B:BC:35:5E:44:28:D8:FD:6E:C2:CD:E3:AB:5F:B9:7A:99:42:98:8E:B8:F4:DC:D0:60:16"); + put("baltimorecybertrustca [jdk]", + "16:AF:57:A9:F6:76:B0:AB:12:60:95:AA:5E:BA:DE:F2:2A:B3:11:19:D6:44:AC:95:CD:4B:93:DB:F3:F2:6A:EB"); + put("digicertglobalrootca [jdk]", +@@ -262,12 +256,6 @@ public class VerifyCACerts { + @SuppressWarnings("serial") + private static final HashSet EXPIRY_EXC_ENTRIES = new HashSet() { + { +- // Valid until: Tue Jul 09 14:40:36 EDT 2019 +- add("utnuserfirstobjectca [jdk]"); +- // Valid until: Sat May 30 10:38:31 GMT 2020 +- add("addtrustexternalca [jdk]"); +- // Valid until: Sat May 30 10:44:50 GMT 2020 +- add("addtrustqualifiedca [jdk]"); + } + }; + diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index 7339448..c67a615 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 12 +Release: 13 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1068,6 +1068,7 @@ Patch139: G1-memory-uncommit.patch Patch140: 8015927-Class-reference-duplicates-in-constant-pool.patch Patch141: 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch Patch142: 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch +Patch143: delete-untrustworthy-cacert.patch ############################################# # @@ -1491,6 +1492,7 @@ pushd %{top_level_dir_name} %patch140 -p1 %patch141 -p1 %patch142 -p1 +%patch143 -p1 popd @@ -2107,6 +2109,9 @@ require "copy_jdk_configs.lua" %endif %changelog +* Wed Dec 23 2020 hubodao - 1:1.8.0.272-b10.12 +- add delete-untrustworthy-cacert.patch + * Wed Dec 23 2020 wujiahua - 1:1.8.0.272-b10.12 - add 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch -- Gitee From 5e02a14dc1a14d78127ac6665efdece822ffebec Mon Sep 17 00:00:00 2001 From: lee18767 Date: Thu, 24 Dec 2020 14:18:04 +0800 Subject: [PATCH 7/7] I2AMW1: add add-appcds-test-case.patch --- add-appcds-test-case.patch | 3720 ++++++++++++++++++++++++++++++++++++ java-1.8.0-openjdk.spec | 15 +- 2 files changed, 3730 insertions(+), 5 deletions(-) create mode 100755 add-appcds-test-case.patch diff --git a/add-appcds-test-case.patch b/add-appcds-test-case.patch new file mode 100755 index 0000000..f5c7db9 --- /dev/null +++ b/add-appcds-test-case.patch @@ -0,0 +1,3720 @@ +diff --git a/hotspot/test/runtime/appcds/AppCDSOptions.java b/hotspot/test/runtime/appcds/AppCDSOptions.java +new file mode 100644 +index 00000000..f5ebb5d5 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/AppCDSOptions.java +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++// This class represents options used for ++// during creation of the archive and/or running JVM with archive ++ ++import com.oracle.java.testlibrary.cds.CDSOptions; ++ ++public class AppCDSOptions extends CDSOptions { ++ public String appJar; ++ ++ // Application classes to be archived ++ public String[] appClasses; ++ ++ public AppCDSOptions setAppJar(String appJar) { ++ this.appJar = appJar; ++ return this; ++ } ++ ++ public AppCDSOptions setAppClasses(String[] appClasses) { ++ this.appClasses = appClasses; ++ return this; ++ } ++ ++} +diff --git a/hotspot/test/runtime/appcds/AppendClasspath.java b/hotspot/test/runtime/appcds/AppendClasspath.java +new file mode 100644 +index 00000000..7ebe7f62 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/AppendClasspath.java +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary At run time, it is OK to append new elements to the classpath that was used at dump time. ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @compile test-classes/HelloMore.java ++ * @run main AppendClasspath ++ */ ++ ++import java.io.File; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class AppendClasspath { ++ ++ public static void main(String[] args) throws Exception { ++ String appJar = JarBuilder.getOrCreateHelloJar(); ++ System.out.println("appJar = "); ++ System.out.println(appJar); ++ String appJar2 = JarBuilder.build("AppendClasspath_HelloMore", "HelloMore"); ++ System.out.println("appJar2 = "); ++ System.out.println(appJar2); ++ // Dump an archive with a specified JAR file in -classpath ++ TestCommon.testDump(appJar, TestCommon.list("Hello")); ++ ++ // PASS: 1) runtime with classpath containing the one used in dump time ++ TestCommon.run( ++ "-cp", appJar + File.pathSeparator + appJar2, ++ "HelloMore") ++ .assertNormalExit(); ++ ++ // PASS: 2) runtime with classpath different from the one used in dump time ++ TestCommon.run( ++ "-cp", appJar2 + File.pathSeparator + appJar, ++ "HelloMore"); ++ ++ // PASS: 3) runtime with classpath part of the one used in dump time ++ TestCommon.testDump(appJar + File.pathSeparator + appJar2, ++ TestCommon.list("Hello")); ++ TestCommon.run( ++ "-cp", appJar2, ++ "Hello"); ++ ++ // PASS: 4) runtime with same set of jar files in the classpath but ++ // with different order ++ TestCommon.run( ++ "-cp", appJar2 + File.pathSeparator + appJar, ++ "HelloMore"); ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/CaseSensitiveClassPath.java b/hotspot/test/runtime/appcds/CaseSensitiveClassPath.java +new file mode 100644 +index 00000000..689d2a17 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/CaseSensitiveClassPath.java +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++ ++/* ++ * @test ++ * @summary Test case sensitive aspect of comparing class paths ++ * between dump time and archive use time ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @run main CaseSensitiveClassPath ++ */ ++ ++import java.nio.file.FileAlreadyExistsException; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.Paths; ++import java.nio.file.StandardCopyOption; ++import com.oracle.java.testlibrary.Platform; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++ ++// Excluded from running on MAC: a more comprehensive case sensitivity detection ++// and fix mechanism is needed, which is planned to be implemented in the future. ++public class CaseSensitiveClassPath { ++ public static void main(String[] args) throws Exception { ++ String appJar = JarBuilder.getOrCreateHelloJar(); ++ String appJarUpper = appJar.replace("hello", "Hello"); ++ ++ OutputAnalyzer out = TestCommon.dump(appJar, TestCommon.list("Hello")); ++ TestCommon.checkDump(out); ++ ++ Path jarPath = Paths.get(appJar); ++ Path jarPathUpper = null; ++ ++ boolean fileExists = false; ++ try { ++ jarPathUpper = Files.createFile(Paths.get(appJarUpper)); ++ } catch (FileAlreadyExistsException faee) { ++ fileExists = true; ++ } ++ ++ if (!fileExists) { ++ try { ++ Files.copy(jarPath, jarPathUpper, StandardCopyOption.REPLACE_EXISTING); ++ } catch (Exception e) { ++ throw new java.lang.RuntimeException( ++ "Failed copying file from " + appJar + " to " + appJarUpper + ".", e); ++ } ++ } else { ++ jarPathUpper = Paths.get(appJarUpper); ++ } ++ boolean isSameFile = Files.isSameFile(jarPath, jarPathUpper); ++ ++ TestCommon.run("-cp", appJarUpper, "Hello", "-Xlog:class+path=info", ++ "-Xlog:cds") ++ .ifNoMappingFailure(output -> { ++ output.shouldContain("Hello World"); ++ }); ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/CommandLineFlagCombo.java b/hotspot/test/runtime/appcds/CommandLineFlagCombo.java +new file mode 100644 +index 00000000..7f7ca7bf +--- /dev/null ++++ b/hotspot/test/runtime/appcds/CommandLineFlagCombo.java +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test CommandLineFlagCombo ++ * @requires (vm.gc=="null") ++ * @summary Test command line flag combinations that ++ * could likely affect the behaviour of AppCDS ++ * @library /testlibrary /testlibrary/whitebox ++ * @build sun.hotspot.WhiteBox ++ * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission ++ * @compile test-classes/Hello.java ++ * @run main/othervm/timeout=240 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. CommandLineFlagCombo ++ */ ++ ++import com.oracle.java.testlibrary.BuildHelper; ++import com.oracle.java.testlibrary.Platform; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++import sun.hotspot.code.Compiler; ++ ++public class CommandLineFlagCombo { ++ ++ // shared base address test table ++ private static final String[] testTable = { ++ "-XX:+UseG1GC", "-XX:+UseSerialGC", "-XX:+UseParallelGC", "-XX:+UseConcMarkSweepGC", ++ "-XX:+FlightRecorder", ++ "-XX:+UseLargePages", // may only take effect on machines with large-pages ++ "-XX:+UseCompressedClassPointers", ++ "-XX:+UseCompressedOops", ++ "-XX:ObjectAlignmentInBytes=16", ++ "-XX:ObjectAlignmentInBytes=32", ++ "-XX:ObjectAlignmentInBytes=64" ++ }; ++ ++ public static void main(String[] args) throws Exception { ++ String appJar = JarBuilder.getOrCreateHelloJar(); ++ String classList[] = {"Hello"}; ++ ++ for (String testEntry : testTable) { ++ System.out.println("CommandLineFlagCombo = " + testEntry); ++ ++ if (skipTestCase(testEntry)) ++ continue; ++ ++ OutputAnalyzer dumpOutput = TestCommon.dump(appJar, classList, testEntry); ++ TestCommon.checkDump(dumpOutput, "Loading classes to share"); ++ ++ OutputAnalyzer execOutput = TestCommon.exec(appJar, testEntry, "Hello"); ++ TestCommon.checkExec(execOutput, "Hello World"); ++ } ++ ++ for (int i=0; i<2; i++) { ++ String g1Flag, serialFlag; ++ ++ // Interned strings are supported only with G1GC. However, we should not crash if: ++ // 0: archive has shared strings, but run time doesn't support shared strings ++ // 1: archive has no shared strings, but run time supports shared strings ++ ++ String dump_g1Flag = "-XX:" + (i == 0 ? "+" : "-") + "UseG1GC"; ++ String run_g1Flag = "-XX:" + (i != 0 ? "+" : "-") + "UseG1GC"; ++ String dump_serialFlag = "-XX:" + (i != 0 ? "+" : "-") + "UseSerialGC"; ++ String run_serialFlag = "-XX:" + (i == 0 ? "+" : "-") + "UseSerialGC"; ++ ++ OutputAnalyzer dumpOutput = TestCommon.dump( ++ appJar, classList, dump_g1Flag, dump_serialFlag); ++ ++ TestCommon.checkDump(dumpOutput, "Loading classes to share"); ++ ++ OutputAnalyzer execOutput = TestCommon.exec(appJar, run_g1Flag, run_serialFlag, "Hello"); ++ TestCommon.checkExec(execOutput, "Hello World"); ++ } ++ } ++ ++ private static boolean skipTestCase(String testEntry) throws Exception { ++ if (Platform.is32bit()) ++ { ++ if (testEntry.equals("-XX:+UseCompressedOops") || ++ testEntry.equals("-XX:+UseCompressedClassPointers") || ++ testEntry.contains("ObjectAlignmentInBytes") ) ++ { ++ System.out.println("Test case not applicable on 32-bit platforms"); ++ return true; ++ } ++ } ++ ++ if (Compiler.isGraalEnabled() && testEntry.equals("-XX:+UseConcMarkSweepGC")) ++ { ++ System.out.println("Graal does not support CMS"); ++ return true; ++ } ++ ++ return false; ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/CommandLineFlagComboNegative.java b/hotspot/test/runtime/appcds/CommandLineFlagComboNegative.java +new file mode 100644 +index 00000000..4fb965ab +--- /dev/null ++++ b/hotspot/test/runtime/appcds/CommandLineFlagComboNegative.java +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test CommandLineFlagComboNegative ++ * @summary Test command line flag combinations that differ between ++ * the dump and execute steps, in such way that they cause errors ++ * E.g. use compressed oops for creating and archive, but then ++ * execute w/o compressed oops ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @run main CommandLineFlagComboNegative ++ */ ++ ++import java.util.ArrayList; ++import com.oracle.java.testlibrary.Platform; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class CommandLineFlagComboNegative { ++ ++ private class TestVector { ++ public String testOptionForDumpStep; ++ public String testOptionForExecuteStep; ++ public String expectedErrorMsg; ++ public int expectedErrorCode; ++ ++ public TestVector(String testOptionForDumpStep, String testOptionForExecuteStep, ++ String expectedErrorMsg, int expectedErrorCode) { ++ this.testOptionForDumpStep=testOptionForDumpStep; ++ this.testOptionForExecuteStep=testOptionForExecuteStep; ++ this.expectedErrorMsg=expectedErrorMsg; ++ this.expectedErrorCode=expectedErrorCode; ++ } ++ } ++ ++ private ArrayList testTable = new ArrayList(); ++ ++ private void initTestTable() { ++ // These options are not applicable on 32-bit platforms ++ if (Platform.is64bit()) { ++ testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=8", "-XX:ObjectAlignmentInBytes=16", ++ "An error has occurred while processing the shared archive file", 1) ); ++ testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=64", "-XX:ObjectAlignmentInBytes=32", ++ "An error has occurred while processing the shared archive file", 1) ); ++ testTable.add( new TestVector("-XX:+UseCompressedOops", "-XX:-UseCompressedOops", ++ "Class data sharing is inconsistent with other specified options", 1) ); ++ testTable.add( new TestVector("-XX:+UseCompressedClassPointers", "-XX:-UseCompressedClassPointers", ++ "Class data sharing is inconsistent with other specified options", 1) ); ++ } ++ } ++ ++ private void runTests() throws Exception ++ { ++ for (TestVector testEntry : testTable) { ++ System.out.println("CommandLineFlagComboNegative: dump = " + testEntry.testOptionForDumpStep); ++ System.out.println("CommandLineFlagComboNegative: execute = " + testEntry.testOptionForExecuteStep); ++ ++ String appJar = JarBuilder.getOrCreateHelloJar(); ++ OutputAnalyzer dumpOutput = TestCommon.dump( ++ appJar, new String[] {"Hello"}, testEntry.testOptionForDumpStep); ++ ++ TestCommon.checkDump(dumpOutput, "Loading classes to share"); ++ ++ TestCommon.run( ++ "-cp", appJar, ++ testEntry.testOptionForExecuteStep, ++ "Hello") ++ .assertAbnormalExit(output -> { ++ output.shouldContain(testEntry.expectedErrorMsg) ++ .shouldHaveExitValue(testEntry.expectedErrorCode); ++ }); ++ } ++ } ++ ++ public static void main(String[] args) throws Exception { ++ CommandLineFlagComboNegative thisClass = new CommandLineFlagComboNegative(); ++ thisClass.initTestTable(); ++ thisClass.runTests(); ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/DirClasspathTest.java b/hotspot/test/runtime/appcds/DirClasspathTest.java +new file mode 100644 +index 00000000..e2c4e698 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/DirClasspathTest.java +@@ -0,0 +1,116 @@ ++/* ++ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Handling of directories in -cp is based on the classlist ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @run main DirClasspathTest ++ */ ++ ++import com.oracle.java.testlibrary.Platform; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++import java.io.File; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.Paths; ++import java.util.Arrays; ++ ++public class DirClasspathTest { ++ private static final int MAX_PATH = 260; ++ ++ public static void main(String[] args) throws Exception { ++ File dir = new File(System.getProperty("user.dir")); ++ File emptydir = new File(dir, "emptydir"); ++ emptydir.mkdir(); ++ ++ ///////////////////////////////////////////////////////////////// ++ // The classlist only contains boot class in following test cases ++ ///////////////////////////////////////////////////////////////// ++ String bootClassList[] = {"java/lang/Object"}; ++ ++ // Empty dir in -cp: should be OK ++ OutputAnalyzer output; ++ output = TestCommon.dump(emptydir.getPath(), bootClassList); ++ TestCommon.checkDump(output); ++ ++ // Long path to empty dir in -cp: should be OK ++ Path classDir = Paths.get(System.getProperty("test.classes")); ++ Path destDir = classDir; ++ int subDirLen = MAX_PATH - classDir.toString().length() - 2; ++ if (subDirLen > 0) { ++ char[] chars = new char[subDirLen]; ++ Arrays.fill(chars, 'x'); ++ String subPath = new String(chars); ++ destDir = Paths.get(System.getProperty("test.classes"), subPath); ++ } ++ File longDir = destDir.toFile(); ++ longDir.mkdir(); ++ File subDir = new File(longDir, "subdir"); ++ subDir.mkdir(); ++ output = TestCommon.dump(subDir.getPath(), bootClassList); ++ TestCommon.checkDump(output); ++ ++ // Non-empty dir in -cp: should be OK ++ // is not empty because it has at least one subdirectory, i.e., ++ output = TestCommon.dump(dir.getPath(), bootClassList); ++ TestCommon.checkDump(output); ++ ++ // Long path to non-empty dir in -cp: should be OK ++ // is not empty because it has at least one subdirectory, i.e., ++ output = TestCommon.dump(longDir.getPath(), bootClassList); ++ TestCommon.checkDump(output); ++ ++ ///////////////////////////////////////////////////////////////// ++ // The classlist contains non-boot class in following test cases ++ ///////////////////////////////////////////////////////////////// ++ String appClassList[] = {"java/lang/Object", "com/sun/tools/javac/Main"}; ++ ++ // Non-empty dir in -cp: should be OK (as long as no classes were loaded from there) ++ output = TestCommon.dump(dir.getPath(), appClassList); ++ TestCommon.checkDump(output); ++ ++ // Long path to non-empty dir in -cp: should be OK (as long as no classes were loaded from there) ++ output = TestCommon.dump(longDir.getPath(), appClassList); ++ TestCommon.checkDump(output); ++ ++ ///////////////////////////////////////////////////////////////// ++ // Loading an app class from a directory ++ ///////////////////////////////////////////////////////////////// ++ String appClassList2[] = {"Hello", "java/lang/Object", "com/sun/tools/javac/Main"}; ++ // Non-empty dir in -cp: should report error if a class is loaded from it ++ output = TestCommon.dump(classDir.toString(), appClassList2); ++ output.shouldNotHaveExitValue(1); ++ output.shouldContain("Cannot find com/sun/tools/javac/Main"); ++ // Long path to non-empty dir in -cp: should report error if a class is loaded from it ++ File srcClass = new File(classDir.toFile(), "Hello.class"); ++ File destClass = new File(longDir, "Hello.class"); ++ Files.copy(srcClass.toPath(), destClass.toPath()); ++ output = TestCommon.dump(longDir.getPath(), appClassList2); ++ output.shouldNotHaveExitValue(1); ++ output.shouldContain("Cannot find Hello"); ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/HelloTest.java b/hotspot/test/runtime/appcds/HelloTest.java +new file mode 100644 +index 00000000..c49179a1 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/HelloTest.java +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Hello World test for AppCDS ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @run main HelloTest ++ */ ++ ++public class HelloTest { ++ public static void main(String[] args) throws Exception { ++ TestCommon.test(JarBuilder.getOrCreateHelloJar(), ++ TestCommon.list("Hello"), "Hello"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/IgnoreEmptyClassPaths.java b/hotspot/test/runtime/appcds/IgnoreEmptyClassPaths.java +new file mode 100644 +index 00000000..36618b17 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/IgnoreEmptyClassPaths.java +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Test the -XX:+IgnoreEmptyClassPaths flag ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @compile test-classes/HelloMore.java ++ * @run main IgnoreEmptyClassPaths ++ */ ++ ++import java.io.File; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class IgnoreEmptyClassPaths { ++ ++ public static void main(String[] args) throws Exception { ++ String jar1 = JarBuilder.getOrCreateHelloJar(); ++ String jar2 = JarBuilder.build("IgnoreEmptyClassPaths_more", "HelloMore"); ++ ++ String sep = File.pathSeparator; ++ String cp_dump = jar1 + sep + jar2 + sep; ++ String cp_exec = sep + jar1 + sep + sep + jar2 + sep; ++ ++ TestCommon.testDump(cp_dump, TestCommon.list("Hello", "HelloMore"), ++ "-XX:+TraceClassPaths", "-XX:+IgnoreEmptyClassPaths"); ++ ++ TestCommon.run( ++ "-verbose:class", ++ "-cp", cp_exec, ++ "-XX:+IgnoreEmptyClassPaths", // should affect classpath even if placed after the "-cp" argument ++ "-XX:+TraceClassPaths", ++ "HelloMore") ++ .assertNormalExit(); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/JarBuilder.java b/hotspot/test/runtime/appcds/JarBuilder.java +new file mode 100644 +index 00000000..e06ab2bc +--- /dev/null ++++ b/hotspot/test/runtime/appcds/JarBuilder.java +@@ -0,0 +1,270 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @summary Simple jar builder ++ * Input: jarName className1 className2 ... ++ * do not specify extensions, just the names ++ * E.g. prot_domain ProtDomainA ProtDomainB ++ * Output: A jar containing compiled classes, placed in a test classes folder ++ * @library /open/test/lib ++ */ ++ ++import java.io.File; ++import java.nio.file.Path; ++import java.util.ArrayList; ++ ++import com.oracle.java.testlibrary.JDKToolFinder; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++import com.oracle.java.testlibrary.ProcessTools; ++import com.oracle.java.testlibrary.compiler.CompilerUtils; ++import sun.tools.jar.Main; ++ ++public class JarBuilder { ++ // to turn DEBUG on via command line: -DJarBuilder.DEBUG=[true, TRUE] ++ private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("JarBuilder.DEBUG", "false")); ++ private static final String classDir = System.getProperty("test.classes"); ++ ++ public static String getJarFilePath(String jarName) { ++ return classDir + File.separator + jarName + ".jar"; ++ } ++ ++ // jar all files under dir, with manifest file man, with an optional versionArgs ++ // for generating a multi-release jar. ++ // The jar command is as follows: ++ // jar cmf \ ++ // \ ++ // -C .\ ++ // --release 9 -C . ++ // the last line begins with "--release" corresponds to the optional versionArgs. ++ public static void build(String jarName, File dir, String man, String...versionArgs) ++ throws Exception { ++ ArrayList args = new ArrayList(); ++ if (man != null) { ++ args.add("cfm"); ++ } else { ++ args.add("cf"); ++ } ++ args.add(classDir + File.separator + jarName + ".jar"); ++ if (man != null) { ++ args.add(man); ++ } ++ args.add("-C"); ++ args.add(dir.getAbsolutePath()); ++ args.add("."); ++ for (String verArg : versionArgs) { ++ args.add(verArg); ++ } ++ createJar(args); ++ } ++ ++ public static String build(String jarName, String...classNames) ++ throws Exception { ++ ++ return createSimpleJar(classDir, getJarFilePath(jarName), classNames); ++ } ++ ++ public static String build(boolean classesInWorkDir, String jarName, String...classNames) ++ throws Exception { ++ if (classesInWorkDir) { ++ return createSimpleJar(".", getJarFilePath(jarName), classNames); ++ } else { ++ return build(jarName, classNames); ++ } ++ } ++ ++ ++ public static String buildWithManifest(String jarName, String manifest, ++ String jarClassesDir, String...classNames) throws Exception { ++ String jarPath = getJarFilePath(jarName); ++ ArrayList args = new ArrayList(); ++ args.add("cvfm"); ++ args.add(jarPath); ++ args.add(System.getProperty("test.src") + File.separator + "test-classes" ++ + File.separator + manifest); ++ addClassArgs(args, jarClassesDir, classNames); ++ createJar(args); ++ ++ return jarPath; ++ } ++ ++ ++ // Execute: jar uvf $jarFile -C $dir . ++ static void update(String jarFile, String dir) throws Exception { ++ String jarExe = JDKToolFinder.getJDKTool("jar"); ++ ++ ArrayList args = new ArrayList<>(); ++ args.add(jarExe); ++ args.add("uvf"); ++ args.add(jarFile); ++ args.add("-C"); ++ args.add(dir); ++ args.add("."); ++ ++ executeProcess(args.toArray(new String[1])); ++ } ++ ++ ++ private static String createSimpleJar(String jarclassDir, String jarName, ++ String[] classNames) throws Exception { ++ ++ ArrayList args = new ArrayList(); ++ args.add("cf"); ++ args.add(jarName); ++ addClassArgs(args, jarclassDir, classNames); ++ createJar(args); ++ ++ return jarName; ++ } ++ ++ private static void addClassArgs(ArrayList args, String jarclassDir, ++ String[] classNames) { ++ ++ for (String name : classNames) { ++ args.add("-C"); ++ args.add(jarclassDir); ++ args.add(name + ".class"); ++ } ++ } ++ ++ public static void createModularJar(String jarPath, ++ String classesDir, ++ String mainClass) throws Exception { ++ ArrayList argList = new ArrayList(); ++ argList.add("--create"); ++ argList.add("--file=" + jarPath); ++ if (mainClass != null) { ++ argList.add("--main-class=" + mainClass); ++ } ++ argList.add("-C"); ++ argList.add(classesDir); ++ argList.add("."); ++ createJar(argList); ++ } ++ ++ private static void createJar(ArrayList args) { ++ if (DEBUG) printIterable("createJar args: ", args); ++ ++ Main jarTool = new Main(System.out, System.err, "jar"); ++ if (!jarTool.run(args.toArray(new String[1]))) { ++ throw new RuntimeException("jar operation failed"); ++ } ++ } ++ ++ // Many AppCDS tests use the same simple "Hello.jar" which contains ++ // simple Hello.class and does not specify additional attributes. ++ // For this common use case, use this method to get the jar path. ++ // The method will check if the jar already exists ++ // (created by another test or test run), and will create the jar ++ // if it does not exist ++ public static String getOrCreateHelloJar() throws Exception { ++ String jarPath = getJarFilePath("hello"); ++ ++ File jarFile = new File(jarPath); ++ if (jarFile.exists()) { ++ return jarPath; ++ } else { ++ return build("hello", "Hello"); ++ } ++ } ++ ++ public static void compile(String dstPath, String source, String... extraArgs) throws Exception { ++ ArrayList args = new ArrayList(); ++ args.add(JDKToolFinder.getCompileJDKTool("javac")); ++ args.add("-d"); ++ args.add(dstPath); ++ if (extraArgs != null) { ++ for (String s : extraArgs) { ++ args.add(s); ++ } ++ } ++ args.add(source); ++ ++ if (DEBUG) printIterable("compile args: ", args); ++ ++ ProcessBuilder pb = new ProcessBuilder(args); ++ OutputAnalyzer output = new OutputAnalyzer(pb.start()); ++ output.shouldHaveExitValue(0); ++ } ++ ++ public static void compileModule(Path src, ++ Path dest, ++ String modulePathArg // arg to --module-path ++ ) throws Exception { ++ boolean compiled = false; ++ if (modulePathArg == null) { ++ compiled = CompilerUtils.compile(src, dest); ++ } else { ++ compiled = CompilerUtils.compile(src, dest, ++ "--module-path", modulePathArg); ++ } ++ if (!compiled) { ++ throw new RuntimeException("module did not compile"); ++ } ++ } ++ ++ ++ public static void signJar() throws Exception { ++ String keyTool = JDKToolFinder.getJDKTool("keytool"); ++ String jarSigner = JDKToolFinder.getJDKTool("jarsigner"); ++ String classDir = System.getProperty("test.classes"); ++ String FS = File.separator; ++ ++ executeProcess(keyTool, ++ "-genkey", "-keystore", "./keystore", "-alias", "mykey", ++ "-storepass", "abc123", "-keypass", "abc123", ++ "-dname", "CN=jvmtest") ++ .shouldHaveExitValue(0); ++ ++ executeProcess(jarSigner, ++ "-keystore", "./keystore", "-storepass", "abc123", "-keypass", ++ "abc123", "-signedjar", classDir + FS + "signed_hello.jar", ++ classDir + FS + "hello.jar", "mykey") ++ .shouldHaveExitValue(0); ++ } ++ ++ private static OutputAnalyzer executeProcess(String... cmds) ++ throws Exception { ++ ++ JarBuilder.printArray("executeProcess: ", cmds); ++ return ProcessTools.executeProcess(new ProcessBuilder(cmds)); ++ } ++ ++ // diagnostic ++ public static void printIterable(String msg, Iterable l) { ++ StringBuilder sum = new StringBuilder(); ++ for (String s : l) { ++ sum.append(s).append(' '); ++ } ++ System.out.println(msg + sum.toString()); ++ } ++ ++ public static void printArray(String msg, String[] l) { ++ StringBuilder sum = new StringBuilder(); ++ for (String s : l) { ++ sum.append(s).append(' '); ++ } ++ System.out.println(msg + sum.toString()); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/MismatchedUseAppCDS.java b/hotspot/test/runtime/appcds/MismatchedUseAppCDS.java +new file mode 100644 +index 00000000..7173d6c9 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/MismatchedUseAppCDS.java +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Try different combination of mismatched UseAppCDS between dump time and run time. ++ * @library /testlibrary /testlibrary/whitebox ++ * @compile test-classes/CheckIfShared.java ++ * @build sun.hotspot.WhiteBox ++ * @run driver ClassFileInstaller sun.hotspot.WhiteBox ++ * @run main MismatchedUseAppCDS ++ */ ++ ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class MismatchedUseAppCDS { ++ public static void main(String[] args) throws Exception { ++ String wbJar = JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox"); ++ String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar; ++ ++ String appJar = JarBuilder.build("MismatchedUseAppCDS", "CheckIfShared"); ++ ++ OutputAnalyzer output; ++ ++ // (1): dump with -XX:+UseAppCDS, but run with -XX:-UseAppCDS ++ TestCommon.testDump(appJar, TestCommon.list("CheckIfShared"), ++ // command-line arguments ... ++ "-XX:+UseAppCDS", ++ use_whitebox_jar); ++ ++ output = TestCommon.exec(appJar, ++ // command-line arguments ... ++ use_whitebox_jar, ++ "-XX:+UnlockDiagnosticVMOptions", ++ "-XX:+WhiteBoxAPI", ++ "CheckIfShared", "false"); ++ TestCommon.checkExec(output); ++ ++ // (2): dump with -XX:-UseAppCDS, but run with -XX:+UseAppCDS ++ TestCommon.testDump(appJar, TestCommon.list("CheckIfShared"), ++ // command-line arguments ... ++ "-XX:+UseAppCDS", ++ use_whitebox_jar); ++ ++ output = TestCommon.exec(appJar, ++ // command-line arguments ... ++ use_whitebox_jar, ++ "-XX:+UseAppCDS", ++ "-XX:+UnlockDiagnosticVMOptions", ++ "-XX:+WhiteBoxAPI", ++ "CheckIfShared", "true"); ++ TestCommon.checkExec(output); ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/MissingSuperTest.java b/hotspot/test/runtime/appcds/MissingSuperTest.java +new file mode 100644 +index 00000000..33a860b4 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/MissingSuperTest.java +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary When super class is missing during dumping, no crash should happen. ++ * @library /testlibrary ++ * @compile test-classes/MissingSuper.java ++ * @run main MissingSuperTest ++ */ ++ ++public class MissingSuperTest { ++ ++ public static void main(String[] args) throws Exception { ++ // The classes "MissingSuperSup" and "MissingSuperIntf" are intentionally not ++ // included into the jar to provoke the test condition ++ JarBuilder.build("missing_super", "MissingSuper", ++ "MissingSuperSub", "MissingSuperImpl"); ++ ++ String appJar = TestCommon.getTestJar("missing_super.jar"); ++ TestCommon.test(appJar, TestCommon.list("MissingSuper", ++ "MissingSuperSub", ++ "MissingSuperImpl"), ++ "MissingSuper"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/PackageSealing.java b/hotspot/test/runtime/appcds/PackageSealing.java +new file mode 100644 +index 00000000..6c915085 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/PackageSealing.java +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary AppCDS handling of package. ++ * @library /testlibrary ++ * @compile test-classes/C1.java ++ * @compile test-classes/C2.java ++ * @compile test-classes/PackageSealingTest.java ++ * @run main PackageSealing ++ */ ++ ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class PackageSealing { ++ public static void main(String args[]) throws Exception { ++ String[] classList = {"sealed/pkg/C1", "pkg/C2", "PackageSealingTest"}; ++ String appJar = ClassFileInstaller.writeJar("pkg_seal.jar", ++ ClassFileInstaller.Manifest.fromSourceFile("test-classes/package_seal.mf"), ++ "PackageSealingTest", "sealed/pkg/C1", "pkg/C2"); ++ ++ // test shared package from -cp path ++ TestCommon.testDump(appJar, TestCommon.list(classList)); ++ OutputAnalyzer output; ++ output = TestCommon.exec(appJar, "PackageSealingTest"); ++ TestCommon.checkExec(output); ++ ++ // test shared package from -Xbootclasspath/a ++ TestCommon.dump(appJar, TestCommon.list(classList), ++ "-Xbootclasspath/a:" + appJar); ++ output = TestCommon.exec(appJar, "-Xbootclasspath/a:" + appJar, "PackageSealingTest"); ++ TestCommon.checkExec(output); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/ParallelLoad2.java b/hotspot/test/runtime/appcds/ParallelLoad2.java +new file mode 100644 +index 00000000..5709be6a +--- /dev/null ++++ b/hotspot/test/runtime/appcds/ParallelLoad2.java +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Load app classes from CDS archive in parallel threads. Similar to ParallelLoad.java, but each class in its own JAR ++ * @library /testlibrary ++ * @compile test-classes/ParallelLoad.java ++ * @compile test-classes/ParallelClasses.java ++ * @run main ParallelLoad2 ++ */ ++ ++import java.io.File; ++ ++public class ParallelLoad2 { ++ public static int MAX_CLASSES = 40; ++ public static void main(String[] args) throws Exception { ++ JarBuilder.build("parallel_load2", "ParallelLoad", "ParallelLoadThread", "ParallelLoadWatchdog"); ++ for (int i=0; i cmd = new ArrayList(); ++ File classList = makeClassList(opts.appClasses); ++ startNewArchiveName(); ++ ++ for (String p : opts.prefix) cmd.add(p); ++ ++ if (opts.appJar != null) { ++ cmd.add("-cp"); ++ cmd.add(opts.appJar); ++ } else { ++ cmd.add("-cp"); ++ cmd.add("\"\""); ++ } ++ ++ cmd.add("-Xshare:dump"); ++// cmd.add("-Xlog:cds,cds+hashtables"); comment out because it will be run by jdk1.8 ++ cmd.add("-XX:ExtraSharedClassListFile=" + classList.getPath()); ++ ++ if (opts.archiveName == null) ++ opts.archiveName = getCurrentArchiveName(); ++ ++ cmd.add("-XX:SharedArchiveFile=" + opts.archiveName); ++ ++ for (String s : opts.suffix) cmd.add(s); ++ ++ String[] cmdLine = cmd.toArray(new String[cmd.size()]); ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, makeCommandLineForAppCDS(cmdLine)); ++ return executeAndLog(pb, "dump"); ++ } ++ ++ ++ // Execute JVM using AppCDS archive with specified AppCDSOptions ++ public static OutputAnalyzer runWithArchive(AppCDSOptions opts) ++ throws Exception { ++ ++ ArrayList cmd = new ArrayList(); ++ ++ for (String p : opts.prefix) cmd.add(p); ++ ++ cmd.add("-Xshare:" + opts.xShareMode); ++ cmd.add("-showversion"); ++ cmd.add("-XX:SharedArchiveFile=" + getCurrentArchiveName()); ++ cmd.add("-Dtest.timeout.factor=" + timeoutFactor); ++ ++ if (opts.appJar != null) { ++ cmd.add("-cp"); ++ cmd.add(opts.appJar); ++ } ++ ++ for (String s : opts.suffix) cmd.add(s); ++ ++ String[] cmdLine = cmd.toArray(new String[cmd.size()]); ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, makeCommandLineForAppCDS(cmdLine)); ++ return executeAndLog(pb, "exec"); ++ } ++ ++ ++ public static OutputAnalyzer execCommon(String... suffix) throws Exception { ++ AppCDSOptions opts = (new AppCDSOptions()); ++ opts.addSuffix(suffix); ++ return runWithArchive(opts); ++ } ++ ++ // This is the new API for running a Java process with CDS enabled. ++ // See comments in the CDSTestUtils.Result class for how to use this method. ++ public static Result run(String... suffix) throws Exception { ++ AppCDSOptions opts = (new AppCDSOptions()); ++ opts.addSuffix(suffix); ++ return new Result(opts, runWithArchive(opts)); ++ } ++ ++ public static OutputAnalyzer exec(String appJar, String... suffix) throws Exception { ++ AppCDSOptions opts = (new AppCDSOptions()).setAppJar(appJar); ++ opts.addSuffix(suffix); ++ return runWithArchive(opts); ++ } ++ ++ public static Result runWithModules(String prefix[], String upgrademodulepath, String modulepath, ++ String mid, String... testClassArgs) throws Exception { ++ AppCDSOptions opts = makeModuleOptions(prefix, upgrademodulepath, modulepath, ++ mid, testClassArgs); ++ return new Result(opts, runWithArchive(opts)); ++ } ++ ++ public static OutputAnalyzer execAuto(String... suffix) throws Exception { ++ AppCDSOptions opts = (new AppCDSOptions()); ++ opts.addSuffix(suffix).setXShareMode("auto"); ++ return runWithArchive(opts); ++ } ++ ++ public static OutputAnalyzer execOff(String... suffix) throws Exception { ++ AppCDSOptions opts = (new AppCDSOptions()); ++ opts.addSuffix(suffix).setXShareMode("off"); ++ return runWithArchive(opts); ++ } ++ ++ ++ private static AppCDSOptions makeModuleOptions(String prefix[], String upgrademodulepath, String modulepath, ++ String mid, String testClassArgs[]) { ++ AppCDSOptions opts = (new AppCDSOptions()); ++ ++ opts.addPrefix(prefix); ++ if (upgrademodulepath == null) { ++ opts.addSuffix("-p", modulepath, "-m", mid); ++ } else { ++ opts.addSuffix("--upgrade-module-path", upgrademodulepath, ++ "-p", modulepath, "-m", mid); ++ } ++ opts.addSuffix(testClassArgs); ++ return opts; ++ } ++ ++ public static OutputAnalyzer execModule(String prefix[], String upgrademodulepath, String modulepath, ++ String mid, String... testClassArgs) ++ throws Exception { ++ AppCDSOptions opts = makeModuleOptions(prefix, upgrademodulepath, modulepath, ++ mid, testClassArgs); ++ return runWithArchive(opts); ++ } ++ ++ ++ // A common operation: dump, then check results ++ public static OutputAnalyzer testDump(String appJar, String appClasses[], ++ String... suffix) throws Exception { ++ OutputAnalyzer output = dump(appJar, appClasses, suffix); ++ output.shouldContain("Loading classes to share"); ++ output.shouldHaveExitValue(0); ++ return output; ++ } ++ ++ ++ /** ++ * Simple test -- dump and execute appJar with the given appClasses in classlist. ++ */ ++ public static OutputAnalyzer test(String appJar, String appClasses[], String... args) ++ throws Exception { ++ testDump(appJar, appClasses); ++ ++ OutputAnalyzer output = exec(appJar, args); ++ return checkExec(output); ++ } ++ ++ ++ public static OutputAnalyzer checkExecReturn(OutputAnalyzer output, int ret, ++ boolean checkContain, String... matches) throws Exception { ++ try { ++ for (String s : matches) { ++ if (checkContain) { ++ output.shouldContain(s); ++ } else { ++ output.shouldNotContain(s); ++ } ++ } ++ output.shouldHaveExitValue(ret); ++ } catch (Exception e) { ++ checkCommonExecExceptions(output, e); ++ } ++ ++ return output; ++ } ++ ++ ++ // Convenience concatenation utils ++ public static String[] list(String ...args) { ++ return args; ++ } ++ ++ ++ public static String[] list(String arg, int count) { ++ ArrayList stringList = new ArrayList(); ++ for (int i = 0; i < count; i++) { ++ stringList.add(arg); ++ } ++ ++ String outputArray[] = stringList.toArray(new String[stringList.size()]); ++ return outputArray; ++ } ++ ++ ++ public static String[] concat(String... args) { ++ return list(args); ++ } ++ ++ ++ public static String[] concat(String prefix[], String... extra) { ++ ArrayList list = new ArrayList(); ++ for (String s : prefix) { ++ list.add(s); ++ } ++ for (String s : extra) { ++ list.add(s); ++ } ++ ++ return list.toArray(new String[list.size()]); ++ } ++ ++ ++ // ===================== Concatenate paths ++ public static String concatPaths(String... paths) { ++ String prefix = ""; ++ String s = ""; ++ for (String p : paths) { ++ s += prefix; ++ s += p; ++ prefix = File.pathSeparator; ++ } ++ return s; ++ } ++ ++ ++ public static String getTestJar(String jar) { ++ File jarFile = CDSTestUtils.getTestArtifact(jar, true); ++ if (!jarFile.isFile()) { ++ throw new RuntimeException("Not a regular file: " + jarFile.getPath()); ++ } ++ return jarFile.getPath(); ++ } ++ ++ ++ public static String getTestDir(String d) { ++ File dirFile = CDSTestUtils.getTestArtifact(d, true); ++ if (!dirFile.isDirectory()) { ++ throw new RuntimeException("Not a directory: " + dirFile.getPath()); ++ } ++ return dirFile.getPath(); ++ } ++ ++ public static boolean checkOutputStrings(String outputString1, ++ String outputString2, ++ String split_regex) { ++ String[] sa1 = outputString1.split(split_regex); ++ String[] sa2 = outputString2.split(split_regex); ++ Arrays.sort(sa1); ++ Arrays.sort(sa2); ++ ++ int i = 0; ++ for (String s : sa1) { ++ if (!s.equals(sa2[i])) { ++ throw new RuntimeException(s + " is different from " + sa2[i]); ++ } ++ i ++; ++ } ++ return true; ++ } ++} +diff --git a/hotspot/test/runtime/appcds/TraceLongClasspath.java b/hotspot/test/runtime/appcds/TraceLongClasspath.java +new file mode 100644 +index 00000000..e25fcd37 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/TraceLongClasspath.java +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary ensure -XX:+TraceClassPaths showing entire expecting app classpath ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @run main TraceLongClasspath ++ */ ++ ++import java.io.File; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class TraceLongClasspath { ++ ++ final static String ps = File.pathSeparator; ++ ++ public static void main(String[] args) throws Exception { ++ String appJar = JarBuilder.getOrCreateHelloJar(); ++ ++ String longClassPath = ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/user-patch.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/abc-startup.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/features/com.foobar.db.jdbc7-dms.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/jdk/lib/tools.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/aaserver/server/lib/someapps.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/aaserver/../foobar_common/modules/net.xy.batcontrib_1.1.0.0_1-0b3/lib/bat-contrib.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/aaserver/modules/features/foobar.aas.common.kkkkkkkkkkk.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.abc.common.adapters_11.1.1/foobar.abc.common.adapters.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.plane.adapter_12.1.3/foobar.plane.adapter.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/lib/ccccccccar-common.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/communications/modules/config.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/communications/modules/userprefs-config.jar" + ps + ++ "/scratch/xxxx/yyyy/XXXXXX/aaaaaaaa/xxxxxxx/xxxxxxxx.us.foobar.com/CommonDomain/config/abc-infra" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/qqqqqq-all-1.6.5.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.abc.thread_11.1.1/foobar.abc.thread.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.abc.thread_11.1.1/thread-rrrrrrr-ext-aas.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.abc.adapter_11.1.1/foobar.abc.adapter.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.abc.ccc_11.1.1/foobar.abc.ccc.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/bbb/lib/commons-configuration.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/bbb/lib/commons-lang.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/bbb/lib/commons-logging.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.wccore/foobar-ppppppp-api.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.ooo_12.1.3/ooo-manifest.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/internal/features/rrr_aaxyxx_foobar.rrr.aas.classpath.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.abc.thread_11.1.1/rrrrrrrr-api.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/commons-xxx-1.1.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/foobar.abc.mgmt_11.1.1/abc-infra-mgmt.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/eee/archives/eee-eee.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/aaserver/common/march/lib/marchnet.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/aaserver/common/march/lib/marchclient.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/aaserver/common/march/lib/march.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/wwcontent/cde/iii/jlib/iiiloader.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/wwcontent/cde/iii/components/xxxxxxyyzzzzz/classes-xxxxxxyyzzzzz.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/wwcontent/cde/iii/components/mmmmmmm/lib/abc_core.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/wwcontent/cde/iii/components/mmmmmmm/lib/abc_codec.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/wwcontent/cde/iii/components/mmmmmmm/lib/abc_imageio.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/jdk/lib/tools.jar" + ps + ++ "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.ooo_12.1.3/ooo-manifest.jar"; ++ ++ String myCP = longClassPath + ps + appJar; ++ // Dump an archive with a specified JAR file in -classpath ++ TestCommon.testDump(myCP, TestCommon.list("Hello")); ++ ++ TestCommon.run( ++ "-XX:+TraceClassPaths", ++ "-cp", appJar, ++ "Hello"); ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/WideIloadTest.java b/hotspot/test/runtime/appcds/WideIloadTest.java +new file mode 100644 +index 00000000..9c045882 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/WideIloadTest.java +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/** ++ * @test ++ * @summary Test 'iload_w' bytecode in shared class ++ * @library /testlibrary ++ * @compile test-classes/Iloadw.jasm ++ * @compile test-classes/IloadwMain.java ++ * @run main WideIloadTest ++ */ ++ ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class WideIloadTest { ++ public static void main(String args[]) throws Exception { ++ JarBuilder.build("iload_w", "Iloadw", "IloadwMain"); ++ String appJar = TestCommon.getTestJar("iload_w.jar"); ++ OutputAnalyzer dumpOutput = TestCommon.dump(appJar, TestCommon.list( ++ "Iloadw", "IloadwMain")); ++ TestCommon.checkDump(dumpOutput); ++ OutputAnalyzer execOutput = TestCommon.exec(appJar, "IloadwMain"); ++ TestCommon.checkExec(execOutput, "Passed"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/XShareAutoWithChangedJar.java b/hotspot/test/runtime/appcds/XShareAutoWithChangedJar.java +new file mode 100644 +index 00000000..f59f2f89 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/XShareAutoWithChangedJar.java +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++/* ++ * @test ++ * @summary Test -Xshare:auto for AppCDS ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @run main XShareAutoWithChangedJar ++ */ ++ ++import com.oracle.java.testlibrary.OutputAnalyzer; ++ ++public class XShareAutoWithChangedJar { ++ public static void main(String[] args) throws Exception { ++ String appJar = JarBuilder.build("XShareAutoWithChangedJar", "Hello"); ++ ++ // 1. dump ++ OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list("Hello")); ++ TestCommon.checkDump(output); ++ ++ // 2. change the jar ++ JarBuilder.build("XShareAutoWithChangedJar", "Hello"); ++ ++ // 3. exec ++ output = TestCommon.execAuto("-cp", appJar, "Hello"); ++ output.shouldContain("Hello World"); ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/test-classes/C1.java b/hotspot/test/runtime/appcds/test-classes/C1.java +new file mode 100644 +index 00000000..86201cd4 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/C1.java +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package sealed.pkg; ++ ++public class C1 { ++} +diff --git a/hotspot/test/runtime/appcds/test-classes/C2.java b/hotspot/test/runtime/appcds/test-classes/C2.java +new file mode 100644 +index 00000000..ad0026fb +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/C2.java +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++package pkg; ++ ++public class C2 { ++} +diff --git a/hotspot/test/runtime/appcds/test-classes/CheckIfShared.java b/hotspot/test/runtime/appcds/test-classes/CheckIfShared.java +new file mode 100644 +index 00000000..59b91f48 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/CheckIfShared.java +@@ -0,0 +1,41 @@ ++/* ++ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++import sun.hotspot.WhiteBox; ++ ++public class CheckIfShared { ++ public static void main(String args[]) throws Exception { ++ WhiteBox wb = WhiteBox.getWhiteBox(); ++ if ("true".equals(args[0])) { ++ if (!wb.isSharedClass(CheckIfShared.class)) { ++ throw new RuntimeException("wb.isSharedClass(CheckIfShared.class) should be true"); ++ } ++ } else { ++ if (wb.isSharedClass(CheckIfShared.class)) { ++ throw new RuntimeException("wb.isSharedClass(CheckIfShared.class) should be false"); ++ } ++ } ++ } ++} ++ +diff --git a/hotspot/test/runtime/appcds/test-classes/Hello.java b/hotspot/test/runtime/appcds/test-classes/Hello.java +new file mode 100644 +index 00000000..dc134771 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/Hello.java +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++public class Hello { ++ public static void main(String args[]) { ++ System.out.println("Hello World"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/test-classes/HelloMore.java b/hotspot/test/runtime/appcds/test-classes/HelloMore.java +new file mode 100644 +index 00000000..0d8f335e +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/HelloMore.java +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++public class HelloMore { ++ public static void main(String args[]) { ++ Hello.main(args); ++ System.out.println("Hello World ... More"); ++ } ++} +diff --git a/hotspot/test/runtime/appcds/test-classes/Iloadw.jasm b/hotspot/test/runtime/appcds/test-classes/Iloadw.jasm +new file mode 100644 +index 00000000..5c1fffbf +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/Iloadw.jasm +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++public class Iloadw ++ version 51: 0 ++{ ++ public static Method run:"()I" ++ stack 1 locals 400 ++ { ++ iconst_0; ++ istore_w 300; ++ iinc_w 300,1; ++ iload_w 300; ++ ireturn; ++ } ++} +diff --git a/hotspot/test/runtime/appcds/test-classes/IloadwMain.java b/hotspot/test/runtime/appcds/test-classes/IloadwMain.java +new file mode 100644 +index 00000000..7257cce6 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/IloadwMain.java +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++public class IloadwMain { ++ public static void main(String args[]) { ++ int result = Iloadw.run(); ++ if (result != 1) { ++ throw new RuntimeException( ++ "Failed. Result is " + result + ", expect 1."); ++ } else { ++ System.out.println("Passed."); ++ } ++ } ++} +diff --git a/hotspot/test/runtime/appcds/test-classes/MissingSuper.java b/hotspot/test/runtime/appcds/test-classes/MissingSuper.java +new file mode 100644 +index 00000000..ef47a7cb +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/MissingSuper.java +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++public class MissingSuper { ++ public static void main(String args[]) { ++ try { ++ new MissingSuperSub(); ++ } catch (NoClassDefFoundError e) { ++ System.out.println("Expected NoClassDefFoundError:"); ++ e.printStackTrace(System.out); ++ } ++ ++ try { ++ new MissingSuperImpl(); ++ } catch (NoClassDefFoundError e) { ++ System.out.println("Expected NoClassDefFoundError:"); ++ e.printStackTrace(System.out); ++ } ++ } ++} ++ ++class MissingSuperSup {} // This class will be deleted from missing_super.jar before dumping ++ ++class MissingSuperSub extends MissingSuperSup {} ++ ++interface MissingSuperIntf {} // This interface will be deleted from missing_super.jar before dumping ++ ++class MissingSuperImpl implements MissingSuperIntf {} +diff --git a/hotspot/test/runtime/appcds/test-classes/PackageSealingTest.java b/hotspot/test/runtime/appcds/test-classes/PackageSealingTest.java +new file mode 100644 +index 00000000..a1e8ea0a +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/PackageSealingTest.java +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++import java.lang.Package; ++ ++public class PackageSealingTest { ++ public static void main(String args[]) { ++ try { ++ Class c1 = PackageSealingTest.class.forName("sealed.pkg.C1"); ++ Class c2 = PackageSealingTest.class.forName("pkg.C2"); ++ Package p1 = c1.getPackage(); ++ System.out.println("Package 1: " + p1.toString()); ++ Package p2 = c2.getPackage(); ++ System.out.println("Package 2: " + p2.toString()); ++ ++ if (!p1.isSealed()) { ++ System.out.println("Failed: sealed.pkg is not sealed."); ++ System.exit(0); ++ } ++ ++ if (p2.isSealed()) { ++ System.out.println("Failed: pkg is sealed."); ++ System.exit(0); ++ } ++ ++ System.out.println("OK"); ++ } catch (Exception e) { ++ System.out.println(e.getMessage()); ++ } ++ } ++} +diff --git a/hotspot/test/runtime/appcds/test-classes/ParallelClasses.java b/hotspot/test/runtime/appcds/test-classes/ParallelClasses.java +new file mode 100644 +index 00000000..a4d0520f +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/ParallelClasses.java +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++class ParallelClass0 {} ++class ParallelClass1 {} ++class ParallelClass2 {} ++class ParallelClass3 {} ++class ParallelClass4 {} ++class ParallelClass5 {} ++class ParallelClass6 {} ++class ParallelClass7 {} ++class ParallelClass8 {} ++class ParallelClass9 {} ++class ParallelClass10 {} ++class ParallelClass11 {} ++class ParallelClass12 {} ++class ParallelClass13 {} ++class ParallelClass14 {} ++class ParallelClass15 {} ++class ParallelClass16 {} ++class ParallelClass17 {} ++class ParallelClass18 {} ++class ParallelClass19 {} ++class ParallelClass20 {} ++class ParallelClass21 {} ++class ParallelClass22 {} ++class ParallelClass23 {} ++class ParallelClass24 {} ++class ParallelClass25 {} ++class ParallelClass26 {} ++class ParallelClass27 {} ++class ParallelClass28 {} ++class ParallelClass29 {} ++class ParallelClass30 {} ++class ParallelClass31 {} ++class ParallelClass32 {} ++class ParallelClass33 {} ++class ParallelClass34 {} ++class ParallelClass35 {} ++class ParallelClass36 {} ++class ParallelClass37 {} ++class ParallelClass38 {} ++class ParallelClass39 {} +diff --git a/hotspot/test/runtime/appcds/test-classes/ParallelLoad.java b/hotspot/test/runtime/appcds/test-classes/ParallelLoad.java +new file mode 100644 +index 00000000..9a6fe550 +--- /dev/null ++++ b/hotspot/test/runtime/appcds/test-classes/ParallelLoad.java +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++import java.io.*; ++import java.net.*; ++import java.lang.reflect.Field; ++ ++ ++// This test helper is parameterized by: ++// - class transformation mode: property "appcds.parallel.transform.mode" ++// - class loader test types ++// ++// In the case of transformMode == "cflh", the transformation is performed ++// by AppCDS/jvmti/TransformerAgent.java. The classes to be transformed, such as ++// ParallelClassTr0, are defined in ./jvmti/parallelLoad/ParallelClasses.java ++ ++public class ParallelLoad { ++ public static int MAX_CLASSES = 40; ++ public static int NUM_THREADS = 4; ++ ++ public final static int SYSTEM_LOADER = 0; ++ public final static int SINGLE_CUSTOM_LOADER = 1; ++ public final static int MULTI_CUSTOM_LOADER = 2; ++ ++ public static final int FINGERPRINT_MODE = 1; ++ public static final int API_MODE = 2; ++ ++ public static int loaderType = SYSTEM_LOADER; ++ public static ClassLoader classLoaders[]; ++ public static int mode = FINGERPRINT_MODE; ++ ++ public static float timeoutFactor = ++ Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); ++ ++ public static void main(String args[]) throws Throwable { ++ run(args, null); ++ } ++ public static void run(String args[], ClassLoader loaders[]) throws Throwable { ++ String customJar = null; ++ System.out.println("ParallelLoad: timeoutFactor = " + timeoutFactor); ++ ++ if (args.length >= 1) { ++ if ("SINGLE_CUSTOM_LOADER".equals(args[0])) { ++ loaderType = SINGLE_CUSTOM_LOADER; ++ customJar = args[2]; ++ } else if ("MULTI_CUSTOM_LOADER".equals(args[0])) { ++ loaderType = MULTI_CUSTOM_LOADER; ++ customJar = args[2]; ++ } else if ("SYSTEM_LOADER".equals(args[0])) { ++ loaderType = SYSTEM_LOADER; ++ } else { ++ throw new RuntimeException("Unexpected loaderType" + args[0]); ++ } ++ } ++ ++ if (customJar != null) { ++ if ("FINGERPRINT_MODE".equals(args[1])) { ++ mode = FINGERPRINT_MODE; ++ classLoaders = new ClassLoader[NUM_THREADS]; ++ for (int i=0; i prefix = new ArrayList(); ++ public ArrayList suffix = new ArrayList(); ++ ++ // Indicate whether to append "-version" when using CDS Archive. ++ // Most of tests will use '-version' ++ public boolean useVersion = true; ++ ++ ++ public CDSOptions() { ++ } ++ ++ ++ public CDSOptions addPrefix(String... prefix) { ++ for (String s : prefix) this.prefix.add(s); ++ return this; ++ } ++ ++ ++ public CDSOptions addSuffix(String... suffix) { ++ for (String s : suffix) this.suffix.add(s); ++ return this; ++ } ++ ++ public CDSOptions setXShareMode(String mode) { ++ this.xShareMode = mode; ++ return this; ++ } ++ ++ ++ public CDSOptions setArchiveName(String name) { ++ this.archiveName = name; ++ return this; ++ } ++ ++ ++ public CDSOptions setUseVersion(boolean use) { ++ this.useVersion = use; ++ return this; ++ } ++} +diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/cds/CDSTestUtils.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cds/CDSTestUtils.java +new file mode 100644 +index 00000000..f1ff7e48 +--- /dev/null ++++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/cds/CDSTestUtils.java +@@ -0,0 +1,590 @@ ++/* ++ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++package com.oracle.java.testlibrary.cds; ++ ++import java.io.File; ++import java.io.FileOutputStream; ++import java.io.IOException; ++import java.io.PrintStream; ++import java.text.SimpleDateFormat; ++import java.util.ArrayList; ++import java.util.Date; ++ ++import com.oracle.java.testlibrary.OutputAnalyzer; ++import com.oracle.java.testlibrary.ProcessTools; ++import com.oracle.java.testlibrary.Utils; ++ ++ ++// This class contains common test utilities for testing CDS ++public class CDSTestUtils { ++ public static final String MSG_RANGE_NOT_WITHIN_HEAP = ++ "UseSharedSpaces: Unable to allocate region, range is not within java heap."; ++ public static final String MSG_RANGE_ALREADT_IN_USE = ++ "Unable to allocate region, java heap range is already in use."; ++ public static final String MSG_COMPRESSION_MUST_BE_USED = ++ "Unable to use shared archive: UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces."; ++ ++ public interface Checker { ++ public void check(OutputAnalyzer output) throws Exception; ++ } ++ ++ /* ++ * INTRODUCTION ++ * ++ * When testing various CDS functionalities, we need to launch JVM processes ++ * using a "launch method" (such as TestCommon.run), and analyze the results of these ++ * processes. ++ * ++ * While typical jtreg tests would use OutputAnalyzer in such cases, due to the ++ * complexity of CDS failure modes, we have added the CDSTestUtils.Result class ++ * to make the analysis more convenient and less error prone. ++ * ++ * A Java process can end in one of the following 4 states: ++ * ++ * 1: Unexpected error - such as JVM crashing. In this case, the "launch method" ++ * will throw a RuntimeException. ++ * 2: Mapping Failure - this happens when the OS (intermittently) fails to map the ++ * CDS archive, normally caused by Address Space Layout Randomization. ++ * We usually treat this as "pass". ++ * 3: Normal Exit - the JVM process has finished without crashing, and the exit code is 0. ++ * 4: Abnormal Exit - the JVM process has finished without crashing, and the exit code is not 0. ++ * ++ * In most test cases, we need to check the JVM process's output in cases 3 and 4. However, we need ++ * to make sure that our test code is not confused by case 2. ++ * ++ * For example, a JVM process is expected to print the string "Hi" and exit with 0. With the old ++ * CDSTestUtils.runWithArchive API, the test may be written as this: ++ * ++ * OutputAnalyzer out = CDSTestUtils.runWithArchive(args); ++ * out.shouldContain("Hi"); ++ * ++ * However, if the JVM process fails with mapping failure, the string "Hi" will not be in the output, ++ * and your test case will fail intermittently. ++ * ++ * Instead, the test case should be written as ++ * ++ * CCDSTestUtils.run(args).assertNormalExit("Hi"); ++ * ++ * EXAMPLES/HOWTO ++ * ++ * 1. For simple substring matching: ++ * ++ * CCDSTestUtils.run(args).assertNormalExit("Hi"); ++ * CCDSTestUtils.run(args).assertNormalExit("a", "b", "x"); ++ * CCDSTestUtils.run(args).assertAbnormalExit("failure 1", "failure2"); ++ * ++ * 2. For more complex output matching: using Lambda expressions ++ * ++ * CCDSTestUtils.run(args) ++ * .assertNormalExit(output -> output.shouldNotContain("this should not be printed"); ++ * CCDSTestUtils.run(args) ++ * .assertAbnormalExit(output -> { ++ * output.shouldNotContain("this should not be printed"); ++ * output.shouldHaveExitValue(123); ++ * }); ++ * ++ * 3. Chaining several checks: ++ * ++ * CCDSTestUtils.run(args) ++ * .assertNormalExit(output -> output.shouldNotContain("this should not be printed") ++ * .assertNormalExit("should have this", "should have that"); ++ * ++ * 4. [Rare use case] if a test sometimes exit normally, and sometimes abnormally: ++ * ++ * CCDSTestUtils.run(args) ++ * .ifNormalExit("ths string is printed when exiting with 0") ++ * .ifAbNormalExit("ths string is printed when exiting with 1"); ++ * ++ * NOTE: you usually don't want to write your test case like this -- it should always ++ * exit with the same exit code. (But I kept this API because some existing test cases ++ * behave this way -- need to revisit). ++ */ ++ public static class Result { ++ private final OutputAnalyzer output; ++ private final CDSOptions options; ++ private final boolean hasMappingFailure; ++ private final boolean hasAbnormalExit; ++ private final boolean hasNormalExit; ++ private final String CDS_DISABLED = "warning: CDS is disabled when the"; ++ ++ public Result(CDSOptions opts, OutputAnalyzer out) throws Exception { ++ options = opts; ++ output = out; ++ hasMappingFailure = CDSTestUtils.checkCommonExecExceptions(output); ++ hasAbnormalExit = (!hasMappingFailure) && (output.getExitValue() != 0); ++ hasNormalExit = (!hasMappingFailure) && (output.getExitValue() == 0); ++ ++ if (hasNormalExit) { ++ if ("on".equals(options.xShareMode) && ++ output.getStderr().contains("java version") && ++ !output.getStderr().contains(CDS_DISABLED)) { ++ // "-showversion" is always passed in the command-line by the execXXX methods. ++ // During normal exit, we require that the VM to show that sharing was enabled. ++ output.shouldContain("sharing"); ++ } ++ } ++ } ++ ++ public Result assertNormalExit(Checker checker) throws Exception { ++ if (!hasMappingFailure) { ++ checker.check(output); ++ output.shouldHaveExitValue(0); ++ } ++ return this; ++ } ++ ++ public Result assertAbnormalExit(Checker checker) throws Exception { ++ if (!hasMappingFailure) { ++ checker.check(output); ++ output.shouldNotHaveExitValue(0); ++ } ++ return this; ++ } ++ ++ // When {--limit-modules, --patch-module, and/or --upgrade-module-path} ++ // are specified, CDS is silently disabled for both -Xshare:auto and -Xshare:on. ++ public Result assertSilentlyDisabledCDS(Checker checker) throws Exception { ++ if (hasMappingFailure) { ++ throw new RuntimeException("Unexpected mapping failure"); ++ } ++ // this comes from a JVM warning message. ++ output.shouldContain(CDS_DISABLED); ++ ++ checker.check(output); ++ return this; ++ } ++ ++ public Result assertSilentlyDisabledCDS(int exitCode, String... matches) throws Exception { ++ return assertSilentlyDisabledCDS((out) -> { ++ out.shouldHaveExitValue(exitCode); ++ checkMatches(out, matches); ++ }); ++ } ++ ++ public Result ifNormalExit(Checker checker) throws Exception { ++ if (hasNormalExit) { ++ checker.check(output); ++ } ++ return this; ++ } ++ ++ public Result ifAbnormalExit(Checker checker) throws Exception { ++ if (hasAbnormalExit) { ++ checker.check(output); ++ } ++ return this; ++ } ++ ++ public Result ifNoMappingFailure(Checker checker) throws Exception { ++ if (!hasMappingFailure) { ++ checker.check(output); ++ } ++ return this; ++ } ++ ++ ++ public Result assertNormalExit(String... matches) throws Exception { ++ if (!hasMappingFailure) { ++ checkMatches(output, matches); ++ output.shouldHaveExitValue(0); ++ } ++ return this; ++ } ++ ++ public Result assertAbnormalExit(String... matches) throws Exception { ++ if (!hasMappingFailure) { ++ checkMatches(output, matches); ++ output.shouldNotHaveExitValue(0); ++ } ++ ++ return this; ++ } ++ } ++ ++ // Specify this property to copy sdandard output of the child test process to ++ // the parent/main stdout of the test. ++ // By default such output is logged into a file, and is copied into the main stdout. ++ public static final boolean CopyChildStdoutToMainStdout = ++ Boolean.valueOf(System.getProperty("test.cds.copy.child.stdout", "true")); ++ ++ // This property is passed to child test processes ++ public static final String TestTimeoutFactor = System.getProperty("test.timeout.factor", "1.0"); ++ ++ public static final String UnableToMapMsg = ++ "Unable to map shared archive: test did not complete; assumed PASS"; ++ ++ // Create bootstrap CDS archive, ++ // use extra JVM command line args as a prefix. ++ // For CDS tests specifying prefix makes more sense than specifying suffix, since ++ // normally there are no classes or arguments to classes, just "-version" ++ // To specify suffix explicitly use CDSOptions.addSuffix() ++ public static OutputAnalyzer createArchive(String... cliPrefix) ++ throws Exception { ++ return createArchive((new CDSOptions()).addPrefix(cliPrefix)); ++ } ++ ++ // Create bootstrap CDS archive ++ public static OutputAnalyzer createArchive(CDSOptions opts) ++ throws Exception { ++ ++ startNewArchiveName(); ++ ++ ArrayList cmd = new ArrayList(); ++ ++ for (String p : opts.prefix) cmd.add(p); ++ ++ cmd.add("-Xshare:dump"); ++ cmd.add("-Xlog:cds,cds+hashtables"); ++ if (opts.archiveName == null) ++ opts.archiveName = getDefaultArchiveName(); ++ cmd.add("-XX:SharedArchiveFile=./" + opts.archiveName); ++ ++ for (String s : opts.suffix) cmd.add(s); ++ ++ String[] cmdLine = cmd.toArray(new String[cmd.size()]); ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmdLine); ++ return executeAndLog(pb, "dump"); ++ } ++ ++ ++ // check result of 'dump-the-archive' operation, that is "-Xshare:dump" ++ public static OutputAnalyzer checkDump(OutputAnalyzer output, String... extraMatches) ++ throws Exception { ++ ++ output.shouldContain("Loading classes to share"); ++ output.shouldHaveExitValue(0); ++ ++ for (String match : extraMatches) { ++ output.shouldContain(match); ++ } ++ ++ return output; ++ } ++ ++ ++ // A commonly used convenience methods to create an archive and check the results ++ // Creates an archive and checks for errors ++ public static OutputAnalyzer createArchiveAndCheck(CDSOptions opts) ++ throws Exception { ++ return checkDump(createArchive(opts)); ++ } ++ ++ ++ public static OutputAnalyzer createArchiveAndCheck(String... cliPrefix) ++ throws Exception { ++ return checkDump(createArchive(cliPrefix)); ++ } ++ ++ ++ // This method should be used to check the output of child VM for common exceptions. ++ // Most of CDS tests deal with child VM processes for creating and using the archive. ++ // However exceptions that occur in the child process do not automatically propagate ++ // to the parent process. This mechanism aims to improve the propagation ++ // of exceptions and common errors. ++ // Exception e argument - an exception to be re-thrown if none of the common ++ // exceptions match. Pass null if you wish not to re-throw any exception. ++ public static boolean checkCommonExecExceptions(OutputAnalyzer output, Exception e) ++ throws Exception { ++ if (output.getStdout().contains("https://bugreport.java.com/bugreport/crash.jsp")) { ++ throw new RuntimeException("Hotspot crashed"); ++ } ++ if (output.getStdout().contains("TEST FAILED")) { ++ throw new RuntimeException("Test Failed"); ++ } ++ if (output.getOutput().contains("Unable to unmap shared space")) { ++ throw new RuntimeException("Unable to unmap shared space"); ++ } ++ ++ // Special case -- sometimes Xshare:on fails because it failed to map ++ // at given address. This behavior is platform-specific, machine config-specific ++ // and can be random (see ASLR). ++ if (isUnableToMap(output)) { ++ System.out.println(UnableToMapMsg); ++ return true; ++ } ++ ++ if (e != null) { ++ throw e; ++ } ++ return false; ++ } ++ ++ public static boolean checkCommonExecExceptions(OutputAnalyzer output) throws Exception { ++ return checkCommonExecExceptions(output, null); ++ } ++ ++ ++ // Check the output for indication that mapping of the archive failed. ++ // Performance note: this check seems to be rather costly - searching the entire ++ // output stream of a child process for multiple strings. However, it is necessary ++ // to detect this condition, a failure to map an archive, since this is not a real ++ // failure of the test or VM operation, and results in a test being "skipped". ++ // Suggestions to improve: ++ // 1. VM can designate a special exit code for such condition. ++ // 2. VM can print a single distinct string indicating failure to map an archive, ++ // instead of utilizing multiple messages. ++ // These are suggestions to improve testibility of the VM. However, implementing them ++ // could also improve usability in the field. ++ public static boolean isUnableToMap(OutputAnalyzer output) { ++ String outStr = output.getOutput(); ++ if ((output.getExitValue() == 1) && ( ++ outStr.contains("Unable to reserve shared space at required address") || ++ outStr.contains("Unable to map ReadOnly shared space at required address") || ++ outStr.contains("Unable to map ReadWrite shared space at required address") || ++ outStr.contains("Unable to map MiscData shared space at required address") || ++ outStr.contains("Unable to map MiscCode shared space at required address") || ++ outStr.contains("Unable to map OptionalData shared space at required address") || ++ outStr.contains("Could not allocate metaspace at a compatible address") || ++ outStr.contains("UseSharedSpaces: Unable to allocate region, range is not within java heap") )) ++ { ++ return true; ++ } ++ ++ return false; ++ } ++ ++ public static Result run(String... cliPrefix) throws Exception { ++ CDSOptions opts = new CDSOptions(); ++ opts.setArchiveName(getDefaultArchiveName()); ++ opts.addPrefix(cliPrefix); ++ return new Result(opts, runWithArchive(opts)); ++ } ++ ++ public static Result run(CDSOptions opts) throws Exception { ++ return new Result(opts, runWithArchive(opts)); ++ } ++ ++ // Execute JVM with CDS archive, specify command line args suffix ++ public static OutputAnalyzer runWithArchive(String... cliPrefix) ++ throws Exception { ++ ++ return runWithArchive( (new CDSOptions()) ++ .setArchiveName(getDefaultArchiveName()) ++ .addPrefix(cliPrefix) ); ++ } ++ ++ ++ // Execute JVM with CDS archive, specify CDSOptions ++ public static OutputAnalyzer runWithArchive(CDSOptions opts) ++ throws Exception { ++ ++ ArrayList cmd = new ArrayList(); ++ ++ for (String p : opts.prefix) cmd.add(p); ++ ++ cmd.add("-Xshare:" + opts.xShareMode); ++ cmd.add("-Dtest.timeout.factor=" + TestTimeoutFactor); ++ ++ if (opts.archiveName == null) ++ opts.archiveName = getDefaultArchiveName(); ++ cmd.add("-XX:SharedArchiveFile=" + opts.archiveName); ++ ++ if (opts.useVersion) ++ cmd.add("-version"); ++ ++ for (String s : opts.suffix) cmd.add(s); ++ ++ String[] cmdLine = cmd.toArray(new String[cmd.size()]); ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmdLine); ++ return executeAndLog(pb, "exec"); ++ } ++ ++ ++ // A commonly used convenience methods to create an archive and check the results ++ // Creates an archive and checks for errors ++ public static OutputAnalyzer runWithArchiveAndCheck(CDSOptions opts) throws Exception { ++ return checkExec(runWithArchive(opts)); ++ } ++ ++ ++ public static OutputAnalyzer runWithArchiveAndCheck(String... cliPrefix) throws Exception { ++ return checkExec(runWithArchive(cliPrefix)); ++ } ++ ++ ++ public static OutputAnalyzer checkExec(OutputAnalyzer output, ++ String... extraMatches) throws Exception { ++ CDSOptions opts = new CDSOptions(); ++ return checkExec(output, opts, extraMatches); ++ } ++ ++ ++ // check result of 'exec' operation, that is when JVM is run using the archive ++ public static OutputAnalyzer checkExec(OutputAnalyzer output, CDSOptions opts, ++ String... extraMatches) throws Exception { ++ try { ++ if ("on".equals(opts.xShareMode)) { ++ output.shouldContain("sharing"); ++ } ++ output.shouldHaveExitValue(0); ++ } catch (RuntimeException e) { ++ checkCommonExecExceptions(output, e); ++ return output; ++ } ++ ++ checkMatches(output, extraMatches); ++ return output; ++ } ++ ++ ++ public static OutputAnalyzer checkExecExpectError(OutputAnalyzer output, ++ int expectedExitValue, ++ String... extraMatches) throws Exception { ++ if (isUnableToMap(output)) { ++ System.out.println(UnableToMapMsg); ++ return output; ++ } ++ ++ output.shouldHaveExitValue(expectedExitValue); ++ checkMatches(output, extraMatches); ++ return output; ++ } ++ ++ public static OutputAnalyzer checkMatches(OutputAnalyzer output, ++ String... matches) throws Exception { ++ for (String match : matches) { ++ output.shouldContain(match); ++ } ++ return output; ++ } ++ ++ ++ // get the file object for the test artifact ++ public static File getTestArtifact(String name, boolean checkExistence) { ++ File dir = new File(System.getProperty("test.classes", ".")); ++ File file = new File(dir, name); ++ ++ if (checkExistence && !file.exists()) { ++ throw new RuntimeException("Cannot find " + file.getPath()); ++ } ++ ++ return file; ++ } ++ ++ ++ // create file containing the specified class list ++ public static File makeClassList(String classes[]) ++ throws Exception { ++ return makeClassList(getTestName() + "-", classes); ++ } ++ ++ // create file containing the specified class list ++ public static File makeClassList(String testCaseName, String classes[]) ++ throws Exception { ++ ++ File classList = getTestArtifact(testCaseName + "test.classlist", false); ++ FileOutputStream fos = new FileOutputStream(classList); ++ PrintStream ps = new PrintStream(fos); ++ ++ addToClassList(ps, classes); ++ ++ ps.close(); ++ fos.close(); ++ ++ return classList; ++ } ++ ++ ++ public static void addToClassList(PrintStream ps, String classes[]) ++ throws IOException ++ { ++ if (classes != null) { ++ for (String s : classes) { ++ ps.println(s); ++ } ++ } ++ } ++ ++ ++ // Optimization for getting a test name. ++ // Test name does not change during execution of the test, ++ // but getTestName() uses stack walking hence it is expensive. ++ // Therefore cache it and reuse it. ++ private static String testName; ++ public static String getTestName() { ++ if (testName == null) { ++ testName = Utils.getTestName(); ++ } ++ return testName; ++ } ++ ++ private static final SimpleDateFormat timeStampFormat = ++ new SimpleDateFormat("HH'h'mm'm'ss's'SSS"); ++ ++ private static String defaultArchiveName; ++ ++ // Call this method to start new archive with new unique name ++ public static void startNewArchiveName() { ++ defaultArchiveName = getTestName() + ++ timeStampFormat.format(new Date()) + ".jsa"; ++ } ++ ++ public static String getDefaultArchiveName() { ++ return defaultArchiveName; ++ } ++ ++ ++ // ===================== FILE ACCESS convenience methods ++ public static File getOutputFile(String name) { ++ File dir = new File(System.getProperty("test.classes", ".")); ++ return new File(dir, getTestName() + "-" + name); ++ } ++ ++ ++ public static File getOutputSourceFile(String name) { ++ File dir = new File(System.getProperty("test.classes", ".")); ++ return new File(dir, name); ++ } ++ ++ ++ public static File getSourceFile(String name) { ++ File dir = new File(System.getProperty("test.src", ".")); ++ return new File(dir, name); ++ } ++ ++ ++ // ============================= Logging ++ public static OutputAnalyzer executeAndLog(ProcessBuilder pb, String logName) throws Exception { ++ long started = System.currentTimeMillis(); ++ OutputAnalyzer output = new OutputAnalyzer(pb.start()); ++ ++ writeFile(getOutputFile(logName + ".stdout"), output.getStdout()); ++ writeFile(getOutputFile(logName + ".stderr"), output.getStderr()); ++ System.out.println("[ELAPSED: " + (System.currentTimeMillis() - started) + " ms]"); ++ System.out.println("[STDERR]\n" + output.getStderr()); ++ ++ if (CopyChildStdoutToMainStdout) ++ System.out.println("[STDOUT]\n" + output.getStdout()); ++ ++ return output; ++ } ++ ++ ++ private static void writeFile(File file, String content) throws Exception { ++ FileOutputStream fos = new FileOutputStream(file); ++ PrintStream ps = new PrintStream(fos); ++ ps.print(content); ++ ps.close(); ++ fos.close(); ++ } ++} +diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/compiler/CompilerUtils.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/compiler/CompilerUtils.java +new file mode 100644 +index 00000000..a02a1742 +--- /dev/null ++++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/compiler/CompilerUtils.java +@@ -0,0 +1,118 @@ ++/* ++ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package com.oracle.java.testlibrary.compiler; ++ ++import java.io.File; ++import java.io.IOException; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.util.Arrays; ++import java.util.Collections; ++import java.util.List; ++import java.util.stream.Collectors; ++ ++import javax.tools.JavaCompiler; ++import javax.tools.StandardJavaFileManager; ++import javax.tools.StandardLocation; ++import javax.tools.ToolProvider; ++ ++/** ++ * This class consists exclusively of static utility methods for invoking the ++ * java compiler. ++ */ ++public final class CompilerUtils { ++ private CompilerUtils() { ++ } ++ ++ /** ++ * Compile all the java sources in {@code /**} to ++ * {@code /**}. The destination directory will be created if ++ * it doesn't exist. ++ *

++ * Equivalent to calling {@code compile(source, destination, true, options);}. ++ *

++ * All warnings/errors emitted by the compiler are output to System.out/err. ++ * ++ * @param source Path to the source directory ++ * @param destination Path to the destination directory ++ * @param options Any options to pass to the compiler ++ * @return true if the compilation is successful ++ * @throws IOException if there is an I/O error scanning the source tree or ++ * creating the destination directory ++ * @throws UnsupportedOperationException if there is no system java compiler ++ */ ++ public static boolean compile(Path source, Path destination, String... options) ++ throws IOException { ++ return compile(source, destination, true, options); ++ } ++ ++ /** ++ * Compile all the java sources in {@code } and optionally its ++ * subdirectories, to ++ * {@code }. The destination directory will be created if ++ * it doesn't exist. ++ *

++ * All warnings/errors emitted by the compiler are output to System.out/err. ++ * ++ * @param source Path to the source directory ++ * @param destination Path to the destination directory ++ * @param recurse If {@code true} recurse into any {@code source} subdirectories ++ * to compile all java source files; else only compile those directly in ++ * {@code source}. ++ * @param options Any options to pass to the compiler ++ * @return true if the compilation is successful ++ * @throws IOException if there is an I/O error scanning the source tree or ++ * creating the destination directory ++ * @throws UnsupportedOperationException if there is no system java compiler ++ */ ++ ++ public static boolean compile(Path source, Path destination, boolean recurse, String... options) ++ throws IOException { ++ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ++ if (compiler == null) { ++ // no compiler available ++ throw new UnsupportedOperationException("Unable to get system java compiler. " ++ + "Perhaps, jdk.compiler module is not available."); ++ } ++ StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null); ++ ++ List sources ++ = Files.find(source, (recurse ? Integer.MAX_VALUE : 1), ++ (file, attrs) -> (file.toString().endsWith(".java"))) ++ .map(e -> e.toFile()) // use jdk1.8 ++ .collect(Collectors.toList()); ++ ++ Files.createDirectories(destination); ++// jfm.setLocation(StandardLocation.CLASS_PATH, Collections.emptyList()); comment out , use jdk1.8, backport from jdk11u ++ jfm.setLocation(StandardLocation.CLASS_OUTPUT, ++ Collections.singletonList(destination.toFile())); ++ ++ List opts = Arrays.asList(options); ++ JavaCompiler.CompilationTask task ++ = compiler.getTask(null, jfm, null, opts, null, ++ jfm.getJavaFileObjectsFromFiles(sources)); // use jdk1.8 ++ ++ return task.call(); ++ } ++} +diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +index 909e09f9..f06b1cbb 100644 +--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java ++++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +@@ -28,9 +28,11 @@ import java.lang.management.MemoryUsage; + import java.lang.reflect.Executable; + import java.util.Arrays; + import java.util.List; ++import java.util.function.BiFunction; + import java.util.function.Function; + import java.util.stream.Stream; + import java.security.BasicPermission; ++import java.util.Objects; + import java.net.URL; + + import sun.hotspot.parser.DiagnosticCommand; +@@ -137,6 +139,31 @@ public class WhiteBox { + } + public native boolean isMethodCompilable(Executable method, int compLevel, boolean isOsr); + public native boolean isMethodQueuedForCompilation(Executable method); ++ ++ // Determine if the compiler corresponding to the compilation level 'compLevel' ++ // and to the compilation context 'compilation_context' provides an intrinsic ++ // for the method 'method'. An intrinsic is available for method 'method' if: ++ // - the intrinsic is enabled (by using the appropriate command-line flag) and ++ // - the platform on which the VM is running provides the instructions necessary ++ // for the compiler to generate the intrinsic code. ++ // ++ // The compilation context is related to using the DisableIntrinsic flag on a ++ // per-method level, see hotspot/src/share/vm/compiler/abstractCompiler.hpp ++ // for more details. ++ public boolean isIntrinsicAvailable(Executable method, ++ Executable compilationContext, ++ int compLevel) { ++ Objects.requireNonNull(method); ++ return isIntrinsicAvailable0(method, compilationContext, compLevel); ++ } ++ // If usage of the DisableIntrinsic flag is not expected (or the usage can be ignored), ++ // use the below method that does not require the compilation context as argument. ++ public boolean isIntrinsicAvailable(Executable method, int compLevel) { ++ return isIntrinsicAvailable(method, null, compLevel); ++ } ++ private native boolean isIntrinsicAvailable0(Executable method, ++ Executable compilationContext, ++ int compLevel); + public int deoptimizeMethod(Executable method) { + return deoptimizeMethod(method, false /*not osr*/); + } +@@ -253,5 +280,4 @@ public class WhiteBox { + // Container testing + public native boolean isContainerized(); + public native void printOsInfo(); +- + } +diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/code/Compiler.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/Compiler.java +new file mode 100644 +index 00000000..bb06f1af +--- /dev/null ++++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/Compiler.java +@@ -0,0 +1,154 @@ ++/* ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++package sun.hotspot.code; ++ ++import java.lang.reflect.Executable; ++import sun.hotspot.WhiteBox; ++ ++/** ++ * API to obtain information about enabled JIT compilers ++ * retrieved from the VM with the WhiteBox API. ++ */ ++public class Compiler { ++ ++ private static final WhiteBox WB = WhiteBox.getWhiteBox(); ++ ++ /** ++ * Check if Graal is used as JIT compiler. ++ * ++ * Graal is enabled if following conditions are true: ++ * - we are not in Interpreter mode ++ * - UseJVMCICompiler flag is true ++ * - jvmci.Compiler variable is equal to 'graal' ++ * - TieredCompilation is not used or TieredStopAtLevel is greater than 3 ++ * No need to check client mode because it set UseJVMCICompiler to false. ++ * ++ * @return true if Graal is used as JIT compiler. ++ */ ++ public static boolean isGraalEnabled() { ++ Boolean useCompiler = WB.getBooleanVMFlag("UseCompiler"); ++ if (useCompiler == null || !useCompiler) { ++ return false; ++ } ++ Boolean useJvmciComp = WB.getBooleanVMFlag("UseJVMCICompiler"); ++ if (useJvmciComp == null || !useJvmciComp) { ++ return false; ++ } ++ // This check might be redundant but let's keep it for now. ++ String jvmciCompiler = System.getProperty("jvmci.Compiler"); ++ if (jvmciCompiler == null || !jvmciCompiler.equals("graal")) { ++ return false; ++ } ++ ++ Boolean tieredCompilation = WB.getBooleanVMFlag("TieredCompilation"); ++ Long compLevel = WB.getIntxVMFlag("TieredStopAtLevel"); ++ // if TieredCompilation is enabled and compilation level is <= 3 then no Graal is used ++ if (tieredCompilation != null && tieredCompilation && ++ compLevel != null && compLevel <= 3) { ++ return false; ++ } ++ return true; ++ } ++ ++ /** ++ * Check if C2 is used as JIT compiler. ++ * ++ * C2 is enabled if following conditions are true: ++ * - we are not in Interpreter mode ++ * - we are in Server compilation mode ++ * - TieredCompilation is not used or TieredStopAtLevel is greater than 3 ++ * - Graal is not used ++ * ++ * @return true if C2 is used as JIT compiler. ++ */ ++ public static boolean isC2Enabled() { ++ Boolean useCompiler = WB.getBooleanVMFlag("UseCompiler"); ++ if (useCompiler == null || !useCompiler) { ++ return false; ++ } ++ Boolean serverMode = WB.getBooleanVMFlag("ProfileInterpreter"); ++ if (serverMode == null || !serverMode) { ++ return false; ++ } ++ ++ Boolean tieredCompilation = WB.getBooleanVMFlag("TieredCompilation"); ++ Long compLevel = WB.getIntxVMFlag("TieredStopAtLevel"); ++ // if TieredCompilation is enabled and compilation level is <= 3 then no Graal is used ++ if (tieredCompilation != null && tieredCompilation && ++ compLevel != null && compLevel <= 3) { ++ return false; ++ } ++ ++ if (isGraalEnabled()) { ++ return false; ++ } ++ ++ return true; ++ } ++ ++ /* ++ * Check if C1 is used as JIT compiler. ++ * ++ * C1 is enabled if following conditions are true: ++ * - we are not in Interpreter mode ++ * - we are not in Server compilation mode ++ * - TieredCompilation is used in Server mode ++ * ++ * @return true if C1 is used as JIT compiler. ++ */ ++ public static boolean isC1Enabled() { ++ Boolean useCompiler = WB.getBooleanVMFlag("UseCompiler"); ++ if (useCompiler == null || !useCompiler) { ++ return false; ++ } ++ Boolean serverMode = WB.getBooleanVMFlag("ProfileInterpreter"); ++ if (serverMode == null || !serverMode) { ++ return true; // Client mode ++ } ++ ++ Boolean tieredCompilation = WB.getBooleanVMFlag("TieredCompilation"); ++ // C1 is not used in server mode if TieredCompilation is off. ++ if (tieredCompilation != null && !tieredCompilation) { ++ return false; ++ } ++ return true; ++ } ++ ++ /* ++ * Determine if the compiler corresponding to the compilation level 'compLevel' ++ * provides an intrinsic for 'class'.'method'. ++ */ ++ public static boolean isIntrinsicAvailable(int compLevel, String klass, String method, Class... parameterTypes) { ++ Executable intrinsicMethod; ++ try { ++ intrinsicMethod = Class.forName(klass).getDeclaredMethod(method, parameterTypes); ++ } catch (NoSuchMethodException e) { ++ throw new RuntimeException("Test bug, '" + method + "' method unavailable. " + e); ++ } catch (ClassNotFoundException e) { ++ throw new RuntimeException("Test bug, '" + klass + "' class unavailable. " + e); ++ } ++ return WB.isIntrinsicAvailable(intrinsicMethod, compLevel); ++ } ++} ++ diff --git a/java-1.8.0-openjdk.spec b/java-1.8.0-openjdk.spec index c67a615..e18a462 100644 --- a/java-1.8.0-openjdk.spec +++ b/java-1.8.0-openjdk.spec @@ -915,7 +915,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 13 +Release: 14 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1069,6 +1069,7 @@ Patch140: 8015927-Class-reference-duplicates-in-constant-pool.patch Patch141: 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch Patch142: 8207160-ClassReader-adjustMethodParams-can-potentially-return-null-if-the-args-list-is-empty.patch Patch143: delete-untrustworthy-cacert.patch +Patch144: add-appcds-test-case.patch ############################################# # @@ -1493,6 +1494,7 @@ pushd %{top_level_dir_name} %patch141 -p1 %patch142 -p1 %patch143 -p1 +%patch144 -p1 popd @@ -2109,7 +2111,10 @@ require "copy_jdk_configs.lua" %endif %changelog -* Wed Dec 23 2020 hubodao - 1:1.8.0.272-b10.12 +* Thu Dec 24 2020 lee18767 - 1:1.8.0.272-b10.14 +- add add-appcds-test-case.patch + +* Wed Dec 23 2020 hubodao - 1:1.8.0.272-b10.13 - add delete-untrustworthy-cacert.patch * Wed Dec 23 2020 wujiahua - 1:1.8.0.272-b10.12 @@ -2118,13 +2123,13 @@ require "copy_jdk_configs.lua" * Wed Dec 23 2020 DataAndOperation - 1:1.8.0.272-b10.11 - add 8040327-Eliminate-AnnotatedType-8040319-Clean-up-type-annotation-exception-index.patch -* Thu Dec 22 2020 miaozhuojun - 1:1.8.0.272-b10.10 +* Tue Dec 22 2020 miaozhuojun - 1:1.8.0.272-b10.10 - add 8015927-Class-reference-duplicates-in-constant-pool.patch -* Thu Dec 22 2020 cruise01 - 1:1.8.0.272-b10.9 +* Tue Dec 22 2020 cruise01 - 1:1.8.0.272-b10.9 - add G1-memory-uncommit.patch -* Thu Dec 22 2020 kuenking - 1:1.8.0.272-b10.8 +* Tue Dec 22 2020 kuenking - 1:1.8.0.272-b10.8 - add add-appcds-file-lock.patch * Mon Dec 21 2020 noah - 1:1.8.0.272-b10.7 -- Gitee