1786 lines
68 KiB
Diff
1786 lines
68 KiB
Diff
---
|
|
make/data/hotspot-symbols/symbols-unix | 1 +
|
|
src/hotspot/share/cds/archiveBuilder.cpp | 3 +-
|
|
src/hotspot/share/cds/dynamicArchive.cpp | 1 -
|
|
src/hotspot/share/cds/filemap.cpp | 76 ++-
|
|
src/hotspot/share/cds/metaspaceShared.cpp | 5 +-
|
|
src/hotspot/share/classfile/classLoader.cpp | 2 +-
|
|
src/hotspot/share/classfile/dictionary.cpp | 2 +-
|
|
src/hotspot/share/classfile/dictionary.hpp | 1 +
|
|
src/hotspot/share/classfile/javaClasses.cpp | 38 ++
|
|
src/hotspot/share/classfile/javaClasses.hpp | 28 +
|
|
src/hotspot/share/classfile/klassFactory.cpp | 53 +-
|
|
.../classfile/systemDictionaryShared.cpp | 522 +++++++++++++++++-
|
|
.../classfile/systemDictionaryShared.hpp | 17 +
|
|
src/hotspot/share/include/cds.h | 1 +
|
|
src/hotspot/share/include/jvm.h | 5 +
|
|
.../jbooster/client/clientDataManager.cpp | 36 ++
|
|
src/hotspot/share/logging/logTag.hpp | 1 +
|
|
src/hotspot/share/prims/jvm.cpp | 23 +-
|
|
src/hotspot/share/runtime/arguments.cpp | 20 +-
|
|
src/hotspot/share/runtime/arguments.hpp | 4 +
|
|
src/hotspot/share/runtime/java.cpp | 3 +-
|
|
src/hotspot/share/utilities/macros.hpp | 8 +
|
|
.../share/classes/java/lang/ClassLoader.java | 20 +
|
|
.../classes/java/net/AggressiveCDSPlugin.java | 203 +++++++
|
|
.../classes/java/net/URLClassLoader.java | 30 +
|
|
.../java/security/SecureClassLoader.java | 14 +
|
|
.../jdk/internal/loader/URLClassPath.java | 18 +
|
|
.../share/native/libjava/ClassLoader.c | 26 +
|
|
28 files changed, 1133 insertions(+), 28 deletions(-)
|
|
create mode 100644 src/java.base/share/classes/java/net/AggressiveCDSPlugin.java
|
|
|
|
diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix
|
|
index 63e5a6946..ac8434902 100644
|
|
--- a/make/data/hotspot-symbols/symbols-unix
|
|
+++ b/make/data/hotspot-symbols/symbols-unix
|
|
@@ -213,3 +213,4 @@ JVM_JBoosterHandleConnection
|
|
JVM_JBoosterPrintStoredClientData
|
|
JVM_JBoosterGetMetaspaceMethodData
|
|
JVM_JBoosterStartupNativeCallback
|
|
+JVM_DefineTrustedSharedClass
|
|
diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp
|
|
index 8e12cdabb..a263f8ecc 100644
|
|
--- a/src/hotspot/share/cds/archiveBuilder.cpp
|
|
+++ b/src/hotspot/share/cds/archiveBuilder.cpp
|
|
@@ -1093,7 +1093,8 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo,
|
|
print_region_stats(mapinfo, closed_heap_regions, open_heap_regions);
|
|
|
|
mapinfo->set_requested_base((char*)MetaspaceShared::requested_base_address());
|
|
- if (mapinfo->header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
|
+ if (mapinfo->header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC
|
|
+ AGGRESSIVE_CDS_ONLY(|| mapinfo->header()->magic() == CDS_AGGRESSIVE_ARCHIVE_MAGIC)) {
|
|
mapinfo->set_header_base_archive_name_size(strlen(Arguments::GetSharedArchivePath()) + 1);
|
|
mapinfo->set_header_base_archive_is_default(FLAG_IS_DEFAULT(SharedArchiveFile));
|
|
}
|
|
diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp
|
|
index 8e3929bc2..5b1176071 100644
|
|
--- a/src/hotspot/share/cds/dynamicArchive.cpp
|
|
+++ b/src/hotspot/share/cds/dynamicArchive.cpp
|
|
@@ -48,7 +48,6 @@
|
|
#include "utilities/align.hpp"
|
|
#include "utilities/bitMap.inline.hpp"
|
|
|
|
-
|
|
class DynamicArchiveBuilder : public ArchiveBuilder {
|
|
public:
|
|
void mark_pointer(address* ptr_loc) {
|
|
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
|
|
index 242b57ee5..fa981d38c 100644
|
|
--- a/src/hotspot/share/cds/filemap.cpp
|
|
+++ b/src/hotspot/share/cds/filemap.cpp
|
|
@@ -67,6 +67,10 @@
|
|
#include "gc/g1/g1CollectedHeap.hpp"
|
|
#include "gc/g1/heapRegion.hpp"
|
|
#endif
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+#include "jbooster/client/clientDataManager.hpp"
|
|
+#include "jbooster/jbooster_globals.hpp"
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
|
|
# include <sys/stat.h>
|
|
# include <errno.h>
|
|
@@ -209,7 +213,14 @@ void FileMapInfo::populate_header(size_t core_region_alignment) {
|
|
|
|
void FileMapHeader::populate(FileMapInfo* mapinfo, size_t core_region_alignment) {
|
|
if (DynamicDumpSharedSpaces) {
|
|
- _magic = CDS_DYNAMIC_ARCHIVE_MAGIC;
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (UseAggressiveCDS) {
|
|
+ _magic = CDS_AGGRESSIVE_ARCHIVE_MAGIC;
|
|
+ } else
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+ {
|
|
+ _magic = CDS_DYNAMIC_ARCHIVE_MAGIC;
|
|
+ }
|
|
} else {
|
|
_magic = CDS_ARCHIVE_MAGIC;
|
|
}
|
|
@@ -396,14 +407,16 @@ bool SharedClassPathEntry::validate(bool is_class_path) const {
|
|
bool ok = true;
|
|
log_info(class, path)("checking shared classpath entry: %s", name);
|
|
if (os::stat(name, &st) != 0 && is_class_path) {
|
|
- // If the archived module path entry does not exist at runtime, it is not fatal
|
|
- // (no need to invalid the shared archive) because the shared runtime visibility check
|
|
- // filters out any archived module classes that do not have a matching runtime
|
|
- // module path location.
|
|
- FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name);
|
|
+ if (!SkipSharedClassPathCheck || !is_dir()) {
|
|
+ // If the archived module path entry does not exist at runtime, it is not fatal
|
|
+ // (no need to invalid the shared archive) because the shared runtime visibility check
|
|
+ // filters out any archived module classes that do not have a matching runtime
|
|
+ // module path location.
|
|
+ FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name);
|
|
+ }
|
|
ok = false;
|
|
} else if (is_dir()) {
|
|
- if (!os::dir_is_empty(name)) {
|
|
+ if (!SkipSharedClassPathCheck && !os::dir_is_empty(name)) {
|
|
FileMapInfo::fail_continue("directory is not empty: %s", name);
|
|
ok = false;
|
|
}
|
|
@@ -533,6 +546,10 @@ int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry
|
|
}
|
|
|
|
void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
|
|
+ if (SkipSharedClassPathCheck) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
Arguments::assert_is_dumping_archive();
|
|
|
|
bool has_nonempty_dir = false;
|
|
@@ -597,7 +614,7 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) {
|
|
const char* file = ClassLoader::skip_uri_protocol(location->as_C_string());
|
|
for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) {
|
|
SharedClassPathEntry* ent = shared_path(i);
|
|
- assert(ent->in_named_module(), "must be");
|
|
+ assert(ent->in_named_module() || SkipSharedClassPathCheck, "must be");
|
|
bool cond = strcmp(file, ent->name()) == 0;
|
|
log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i,
|
|
location->as_C_string(), ent->name(), cond ? "same" : "different");
|
|
@@ -798,6 +815,9 @@ bool FileMapInfo::validate_boot_class_paths() {
|
|
}
|
|
|
|
bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
|
|
+ if (SkipSharedClassPathCheck) {
|
|
+ return true;
|
|
+ }
|
|
const char *appcp = Arguments::get_appclasspath();
|
|
assert(appcp != NULL, "NULL app classpath");
|
|
int rp_len = num_paths(appcp);
|
|
@@ -988,7 +1008,8 @@ bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
|
|
}
|
|
} else {
|
|
DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)header;
|
|
- if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
|
+ if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC
|
|
+ AGGRESSIVE_CDS_ONLY(&& dynamic_header->magic() != CDS_AGGRESSIVE_ARCHIVE_MAGIC)) {
|
|
os::free(header);
|
|
os::close(fd);
|
|
vm_exit_during_initialization("Not a top shared archive", archive_name);
|
|
@@ -1018,7 +1039,8 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
|
|
os::close(fd);
|
|
return false;
|
|
}
|
|
- if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
|
+ if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC
|
|
+ AGGRESSIVE_CDS_ONLY(&& dynamic_header->magic() != CDS_AGGRESSIVE_ARCHIVE_MAGIC)) {
|
|
// Not a dynamic header, no need to proceed further.
|
|
*size = 0;
|
|
os::free(dynamic_header);
|
|
@@ -1068,6 +1090,13 @@ bool FileMapInfo::init_from_file(int fd) {
|
|
}
|
|
|
|
unsigned int expected_magic = is_static() ? CDS_ARCHIVE_MAGIC : CDS_DYNAMIC_ARCHIVE_MAGIC;
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (UseAggressiveCDS && !is_static()) {
|
|
+ expected_magic = CDS_AGGRESSIVE_ARCHIVE_MAGIC;
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
if (header()->magic() != expected_magic) {
|
|
log_info(cds)("_magic expected: 0x%08x", expected_magic);
|
|
log_info(cds)(" actual: 0x%08x", header()->magic());
|
|
@@ -1186,10 +1215,21 @@ void FileMapInfo::open_for_write(const char* path) {
|
|
chmod(_full_path, _S_IREAD | _S_IWRITE);
|
|
#endif
|
|
|
|
- // Use remove() to delete the existing file because, on Unix, this will
|
|
- // allow processes that have it open continued access to the file.
|
|
- remove(_full_path);
|
|
- int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444);
|
|
+ int fd;
|
|
+#if INCLUDE_JBOOSTER
|
|
+ if (UseJBooster && ClientDataManager::get().is_cds_allowed()) {
|
|
+ // The _full_path points to the tmp file in the JBooster environment.
|
|
+ // The tmp file should have been created before (see dump_cds() in
|
|
+ // clientMessageHandler.cpp). So do not remove it or try to create it.
|
|
+ fd = os::open(_full_path, O_RDWR | O_TRUNC | O_BINARY, 0);
|
|
+ } else
|
|
+#endif // INCLUDE_JBOOSTER
|
|
+ {
|
|
+ // Use remove() to delete the existing file because, on Unix, this will
|
|
+ // allow processes that have it open continued access to the file.
|
|
+ remove(_full_path);
|
|
+ fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444);
|
|
+ }
|
|
if (fd < 0) {
|
|
fail_stop("Unable to create shared archive file %s: (%s).", _full_path,
|
|
os::strerror(errno));
|
|
@@ -1200,7 +1240,8 @@ void FileMapInfo::open_for_write(const char* path) {
|
|
// Seek past the header. We will write the header after all regions are written
|
|
// and their CRCs computed.
|
|
size_t header_bytes = header()->header_size();
|
|
- if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
|
+ if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC
|
|
+ AGGRESSIVE_CDS_ONLY(|| header()->magic() == CDS_AGGRESSIVE_ARCHIVE_MAGIC)) {
|
|
header_bytes += strlen(Arguments::GetSharedArchivePath()) + 1;
|
|
}
|
|
|
|
@@ -1218,7 +1259,8 @@ void FileMapInfo::write_header() {
|
|
assert(is_file_position_aligned(), "must be");
|
|
write_bytes(header(), header()->header_size());
|
|
|
|
- if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
|
+ if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC
|
|
+ AGGRESSIVE_CDS_ONLY(|| header()->magic() == CDS_AGGRESSIVE_ARCHIVE_MAGIC)) {
|
|
char* base_archive_name = (char*)Arguments::GetSharedArchivePath();
|
|
if (base_archive_name != NULL) {
|
|
write_bytes(base_archive_name, header()->base_archive_name_size());
|
|
@@ -2328,7 +2370,7 @@ ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) {
|
|
ClassPathEntry* ent = _classpath_entries_for_jvmti[i];
|
|
if (ent == NULL) {
|
|
SharedClassPathEntry* scpe = shared_path(i);
|
|
- assert(scpe->is_jar(), "must be"); // other types of scpe will not produce archived classes
|
|
+ assert(scpe->is_jar() || SkipSharedClassPathCheck, "must be"); // other types of scpe will not produce archived classes
|
|
|
|
const char* path = scpe->name();
|
|
struct stat st;
|
|
diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp
|
|
index 87ff93fb4..f4c8d0f81 100644
|
|
--- a/src/hotspot/share/cds/metaspaceShared.cpp
|
|
+++ b/src/hotspot/share/cds/metaspaceShared.cpp
|
|
@@ -76,6 +76,9 @@
|
|
#if INCLUDE_G1GC
|
|
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
|
#endif
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+#include "jbooster/jbooster_globals.hpp"
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
|
|
ReservedSpace MetaspaceShared::_symbol_rs;
|
|
VirtualSpace MetaspaceShared::_symbol_vs;
|
|
@@ -573,7 +576,7 @@ public:
|
|
bool MetaspaceShared::linking_required(InstanceKlass* ik) {
|
|
// For static CDS dump, do not link old classes.
|
|
// For dynamic CDS dump, only link classes loaded by the builtin class loaders.
|
|
- return DumpSharedSpaces ? ik->can_be_verified_at_dumptime() : !ik->is_shared_unregistered_class();
|
|
+ return DumpSharedSpaces ? ik->can_be_verified_at_dumptime() : !ik->is_shared_unregistered_class() AGGRESSIVE_CDS_ONLY(|| UseAggressiveCDS);
|
|
}
|
|
|
|
bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) {
|
|
diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
|
|
index 05561110a..6e9b9bcdf 100644
|
|
--- a/src/hotspot/share/classfile/classLoader.cpp
|
|
+++ b/src/hotspot/share/classfile/classLoader.cpp
|
|
@@ -1315,7 +1315,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, const Cl
|
|
(i < ClassLoaderExt::app_class_paths_start_index())) {
|
|
// The class must be from boot loader append path which consists of
|
|
// -Xbootclasspath/a and jvmti appended entries.
|
|
- assert(loader == NULL, "sanity");
|
|
+ assert(loader == NULL || SkipSharedClassPathCheck, "sanity");
|
|
classpath_index = i;
|
|
break;
|
|
}
|
|
diff --git a/src/hotspot/share/classfile/dictionary.cpp b/src/hotspot/share/classfile/dictionary.cpp
|
|
index 9905eb4fc..3034a5eba 100644
|
|
--- a/src/hotspot/share/classfile/dictionary.cpp
|
|
+++ b/src/hotspot/share/classfile/dictionary.cpp
|
|
@@ -640,4 +640,4 @@ void Dictionary::verify() {
|
|
stringStream tempst;
|
|
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
|
|
verify_table<DictionaryEntry>(tempst.as_string());
|
|
-}
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/hotspot/share/classfile/dictionary.hpp b/src/hotspot/share/classfile/dictionary.hpp
|
|
index e42b60cf0..28dfff309 100644
|
|
--- a/src/hotspot/share/classfile/dictionary.hpp
|
|
+++ b/src/hotspot/share/classfile/dictionary.hpp
|
|
@@ -44,6 +44,7 @@ class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
|
|
static bool _some_dictionary_needs_resizing;
|
|
bool _resizable;
|
|
bool _needs_resizing;
|
|
+
|
|
void check_if_needs_resize();
|
|
|
|
ClassLoaderData* _loader_data; // backpointer to owning loader
|
|
diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
|
|
index bf817989d..24cc928e4 100644
|
|
--- a/src/hotspot/share/classfile/javaClasses.cpp
|
|
+++ b/src/hotspot/share/classfile/javaClasses.cpp
|
|
@@ -5066,6 +5066,44 @@ void java_lang_InternalError::serialize_offsets(SerializeClosure* f) {
|
|
}
|
|
#endif
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+int java_security_ProtectionDomain::_code_source_offset;
|
|
+
|
|
+oop java_security_ProtectionDomain::codeSource(oop protection_domain) {
|
|
+ return protection_domain->obj_field(_code_source_offset);
|
|
+}
|
|
+
|
|
+#define PROTECTIONDOMAIN_FIELDS_DO(macro) \
|
|
+ macro(_code_source_offset, k, "codesource", codesource_signature, false)
|
|
+
|
|
+void java_security_ProtectionDomain::compute_offsets() {
|
|
+ InstanceKlass* k = vmClasses::ProtectionDomain_klass();
|
|
+ PROTECTIONDOMAIN_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
|
+}
|
|
+
|
|
+void java_security_ProtectionDomain::serialize_offsets(SerializeClosure* f) {
|
|
+ PROTECTIONDOMAIN_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
|
+}
|
|
+
|
|
+int java_security_CodeSource::_locationNoFragString_offset;
|
|
+
|
|
+oop java_security_CodeSource::locationNoFragString(oop code_source) {
|
|
+ return code_source->obj_field(_locationNoFragString_offset);
|
|
+}
|
|
+
|
|
+#define CODESOURCE_FIELDS_DO(macro) \
|
|
+ macro(_locationNoFragString_offset, k, "locationNoFragString", string_signature, false)
|
|
+
|
|
+void java_security_CodeSource::compute_offsets() {
|
|
+ InstanceKlass* k = vmClasses::CodeSource_klass();
|
|
+ CODESOURCE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
|
+}
|
|
+
|
|
+void java_security_CodeSource::serialize_offsets(SerializeClosure* f) {
|
|
+ CODESOURCE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
|
+}
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
#define DO_COMPUTE_OFFSETS(k) k::compute_offsets();
|
|
|
|
// Compute field offsets of all the classes in this file
|
|
diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp
|
|
index f18838781..2a769ea83 100644
|
|
--- a/src/hotspot/share/classfile/javaClasses.hpp
|
|
+++ b/src/hotspot/share/classfile/javaClasses.hpp
|
|
@@ -79,6 +79,8 @@ class RecordComponent;
|
|
f(jdk_internal_misc_UnsafeConstants) \
|
|
f(java_lang_boxing_object) \
|
|
f(vector_VectorPayload) \
|
|
+ AGGRESSIVE_CDS_ONLY(f(java_security_ProtectionDomain)) \
|
|
+ AGGRESSIVE_CDS_ONLY(f(java_security_CodeSource)) \
|
|
//end
|
|
|
|
#define BASIC_JAVA_CLASSES_DO(f) \
|
|
@@ -1744,6 +1746,32 @@ class java_lang_InternalError : AllStatic {
|
|
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
|
};
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+class java_security_ProtectionDomain : AllStatic {
|
|
+ private:
|
|
+ static int _code_source_offset;
|
|
+
|
|
+ public:
|
|
+ static void compute_offsets();
|
|
+
|
|
+ static void serialize_offsets(SerializeClosure* f);
|
|
+
|
|
+ static oop codeSource(oop protection_domain);
|
|
+};
|
|
+
|
|
+class java_security_CodeSource : AllStatic {
|
|
+ private:
|
|
+ static int _locationNoFragString_offset;
|
|
+
|
|
+ public:
|
|
+ static void compute_offsets();
|
|
+
|
|
+ static void serialize_offsets(SerializeClosure* f);
|
|
+
|
|
+ static oop locationNoFragString(oop code_source);
|
|
+};
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
// Use to declare fields that need to be injected into Java classes
|
|
// for the JVM to use. The name_index and signature_index are
|
|
// declared in vmSymbols. The may_be_java flag is used to declare
|
|
diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp
|
|
index 7b5960ee3..52079b898 100644
|
|
--- a/src/hotspot/share/classfile/klassFactory.cpp
|
|
+++ b/src/hotspot/share/classfile/klassFactory.cpp
|
|
@@ -40,6 +40,10 @@
|
|
#if INCLUDE_JFR
|
|
#include "jfr/support/jfrKlassExtension.hpp"
|
|
#endif
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+#include "classfile/systemDictionaryShared.hpp"
|
|
+#include "jbooster/jbooster_globals.hpp"
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
|
|
|
|
// called during initial loading of a shared class
|
|
@@ -58,7 +62,18 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
|
// Post the CFLH
|
|
JvmtiCachedClassFileData* cached_class_file = NULL;
|
|
if (cfs == NULL) {
|
|
- cfs = FileMapInfo::open_stream_for_jvmti(ik, class_loader, CHECK_NULL);
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (UseAggressiveCDS && !SystemDictionaryShared::is_builtin(ik)) {
|
|
+ assert(UseAggressiveCDS, "sanity check");
|
|
+ cfs = SystemDictionaryShared::get_shared_class_file_stream(ik);
|
|
+ if (cfs == NULL) {
|
|
+ cfs = SystemDictionaryShared::get_byte_code_from_cache(class_name, class_loader, CHECK_NULL);
|
|
+ }
|
|
+ } else
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+ {
|
|
+ cfs = FileMapInfo::open_stream_for_jvmti(ik, class_loader, CHECK_NULL);
|
|
+ }
|
|
}
|
|
unsigned char* ptr = (unsigned char*)cfs->buffer();
|
|
unsigned char* end_ptr = ptr + cfs->length();
|
|
@@ -69,7 +84,7 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
|
&ptr,
|
|
&end_ptr,
|
|
&cached_class_file);
|
|
- if (old_ptr != ptr) {
|
|
+ if (old_ptr != ptr AGGRESSIVE_CDS_ONLY(|| (UseAggressiveCDS && !SystemDictionaryShared::is_builtin(ik)))) {
|
|
// JVMTI agent has modified class file data.
|
|
// Set new class file stream using JVMTI agent modified class file data.
|
|
ClassLoaderData* loader_data =
|
|
@@ -79,6 +94,19 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
|
end_ptr - ptr,
|
|
cfs->source(),
|
|
ClassFileStream::verify);
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (UseAggressiveCDS) {
|
|
+ int stream_size = stream->length();
|
|
+ int stream_crc32 = ClassLoader::crc32(0, (const char*)stream->buffer(), stream->length());
|
|
+ uint64_t fingerprint = (uint64_t(stream_size) << 32) | uint64_t(uint32_t(stream_crc32));
|
|
+ if (ik->get_stored_fingerprint() == fingerprint) {
|
|
+ if (cached_class_file != NULL) {
|
|
+ ik->set_cached_class_file(cached_class_file);
|
|
+ }
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
ClassLoadInfo cl_info(protection_domain);
|
|
ClassFileParser parser(stream,
|
|
class_name,
|
|
@@ -212,6 +240,27 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
|
|
#if INCLUDE_CDS
|
|
if (Arguments::is_dumping_archive()) {
|
|
ClassLoader::record_result(THREAD, result, stream);
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (UseAggressiveCDS && !loader_data->is_builtin_class_loader_data()) {
|
|
+ if (Arguments::init_agents_at_startup() && !cl_info.is_hidden()) {
|
|
+ SystemDictionaryShared::set_shared_class_file(result, old_stream);
|
|
+ }
|
|
+ Handle protection_domain = cl_info.protection_domain();
|
|
+ if (protection_domain.not_null()) {
|
|
+ Handle codesource(THREAD, java_security_ProtectionDomain::codeSource(protection_domain()));
|
|
+ if (codesource.not_null()) {
|
|
+ Handle str(THREAD, java_security_CodeSource::locationNoFragString(codesource()));
|
|
+ if (str.not_null()) {
|
|
+ char* string_value = java_lang_String::as_utf8_string(str());
|
|
+ if (strlen(string_value) != 0) {
|
|
+ SystemDictionaryShared::set_url_string(result, string_value);
|
|
+ SystemDictionaryShared::save_timestamp(result, string_value);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
}
|
|
#endif // INCLUDE_CDS
|
|
|
|
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp
|
|
index a055ad741..ee4bd6f24 100644
|
|
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
|
|
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
|
|
@@ -69,7 +69,14 @@
|
|
#include "utilities/hashtable.inline.hpp"
|
|
#include "utilities/resourceHash.hpp"
|
|
#include "utilities/stringUtils.hpp"
|
|
-
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+#include "jbooster/client/clientStartupSignal.hpp"
|
|
+#include "jbooster/jbooster_globals.hpp"
|
|
+#include "jbooster/utilities/debugUtils.inline.hpp"
|
|
+#include "jbooster/utilities/scalarHashMap.inline.hpp"
|
|
+#include "memory/oopFactory.hpp"
|
|
+#include "runtime/javaCalls.hpp"
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
|
|
OopHandle SystemDictionaryShared::_shared_protection_domains;
|
|
OopHandle SystemDictionaryShared::_shared_jar_urls;
|
|
@@ -107,6 +114,14 @@ public:
|
|
}
|
|
};
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ struct DTSharedData {
|
|
+ int length;
|
|
+ u1 data[1];
|
|
+ int obj_size() { return sizeof(length) + length; }
|
|
+ };
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
InstanceKlass* _klass;
|
|
InstanceKlass* _nest_host;
|
|
bool _failed_verification;
|
|
@@ -117,6 +132,11 @@ public:
|
|
GrowableArray<DTVerifierConstraint>* _verifier_constraints;
|
|
GrowableArray<char>* _verifier_constraint_flags;
|
|
GrowableArray<DTLoaderConstraint>* _loader_constraints;
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ DTSharedData* _shared_class_file;
|
|
+ DTSharedData* _url_string;
|
|
+ int64_t _classfile_timestamp;
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
|
|
DumpTimeSharedClassInfo() {
|
|
_klass = NULL;
|
|
@@ -132,6 +152,11 @@ public:
|
|
_verifier_constraints = NULL;
|
|
_verifier_constraint_flags = NULL;
|
|
_loader_constraints = NULL;
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ _shared_class_file = NULL;
|
|
+ _url_string = NULL;
|
|
+ _classfile_timestamp = 0;
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
}
|
|
|
|
void add_verification_constraint(InstanceKlass* k, Symbol* name,
|
|
@@ -194,6 +219,72 @@ public:
|
|
void set_failed_verification() { _failed_verification = true; }
|
|
InstanceKlass* nest_host() const { return _nest_host; }
|
|
void set_nest_host(InstanceKlass* nest_host) { _nest_host = nest_host; }
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ DTSharedData* shared_class_file() {
|
|
+ return _shared_class_file;
|
|
+ }
|
|
+
|
|
+ int shared_class_file_size() {
|
|
+ if (_shared_class_file != NULL) {
|
|
+ return _shared_class_file->obj_size();
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ void copy_shared_class_file(ClassFileStream* cfs) {
|
|
+ assert(_shared_class_file == NULL, "already have _shared_class_file");
|
|
+ int stream_length = cfs->length();
|
|
+ int size = offset_of(DTSharedData, data) + stream_length;
|
|
+ _shared_class_file = (DTSharedData*) NEW_C_HEAP_ARRAY(u1, size, mtJBooster);
|
|
+ _shared_class_file->length = stream_length;
|
|
+ memcpy(_shared_class_file->data, cfs->buffer(), stream_length);
|
|
+ assert(size == _shared_class_file->obj_size(), "sanity");
|
|
+ }
|
|
+
|
|
+ void free_shared_class_file() {
|
|
+ if (_shared_class_file != NULL) {
|
|
+ FREE_C_HEAP_ARRAY(u1, _shared_class_file);
|
|
+ _shared_class_file = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ DTSharedData* url_string() {
|
|
+ return _url_string;
|
|
+ }
|
|
+
|
|
+ int url_string_size() {
|
|
+ if (_url_string != NULL) {
|
|
+ return _url_string->obj_size();
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ void copy_url_string(char* string_value) {
|
|
+ assert(strlen(string_value) != 0, "sanity");
|
|
+ int string_len = strlen(string_value) + 1;
|
|
+ int size = offset_of(DTSharedData, data) + string_len;
|
|
+ _url_string = (DTSharedData*) NEW_C_HEAP_ARRAY(u1, size, mtJBooster);
|
|
+ _url_string->length = string_len;
|
|
+ memcpy(_url_string->data, string_value, string_len);
|
|
+ assert(size == _url_string->obj_size(), "sanity");
|
|
+ }
|
|
+
|
|
+ void free_url_string() {
|
|
+ if (_url_string != NULL) {
|
|
+ FREE_C_HEAP_ARRAY(u1, _url_string);
|
|
+ _url_string = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ int64_t classfile_timestamp() {
|
|
+ return _classfile_timestamp;
|
|
+ }
|
|
+
|
|
+ void set_classfile_timestamp(int64_t classfile_timestamp) {
|
|
+ _classfile_timestamp = classfile_timestamp;
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
};
|
|
|
|
inline unsigned DumpTimeSharedClassTable_hash(InstanceKlass* const& k) {
|
|
@@ -472,7 +563,20 @@ public:
|
|
}
|
|
};
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ struct RTSharedData {
|
|
+ int length;
|
|
+ u1 data[1];
|
|
+ int obj_size() { return sizeof(length) + length; }
|
|
+ };
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
InstanceKlass* _klass;
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ RTSharedData* _shared_class_file;
|
|
+ RTSharedData* _url_string;
|
|
+ int64_t _classfile_timestamp;
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
int _num_verifier_constraints;
|
|
int _num_loader_constraints;
|
|
|
|
@@ -509,6 +613,11 @@ private:
|
|
return 0;
|
|
}
|
|
}
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ static size_t shared_class_file_size(DumpTimeSharedClassInfo& info) {
|
|
+ return info.shared_class_file_size();
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
|
|
public:
|
|
static size_t byte_size(InstanceKlass* klass, int num_verifier_constraints, int num_loader_constraints) {
|
|
@@ -520,6 +629,23 @@ public:
|
|
verifier_constraint_flags_size(num_verifier_constraints);
|
|
}
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ static size_t byte_size(DumpTimeSharedClassInfo& info) {
|
|
+ size_t previous_size = byte_size(info._klass, info.num_verifier_constraints(), info.num_loader_constraints());
|
|
+ if (UseAggressiveCDS) {
|
|
+ size_t cf_size = shared_class_file_size(info);
|
|
+ if (cf_size != 0) {
|
|
+ previous_size = align_up(previous_size, sizeof(int)) + cf_size;
|
|
+ }
|
|
+ cf_size = info.url_string_size();
|
|
+ if (cf_size != 0) {
|
|
+ return align_up(previous_size, sizeof(int)) + cf_size;
|
|
+ }
|
|
+ }
|
|
+ return previous_size;
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
private:
|
|
size_t crc_offset() const {
|
|
return header_size_size();
|
|
@@ -547,6 +673,20 @@ private:
|
|
assert(0 <= i && i < _num_loader_constraints, "sanity");
|
|
}
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ size_t shared_class_file_offset() const {
|
|
+ return align_up(verifier_constraint_flags_offset() + verifier_constraint_flags_size(_num_verifier_constraints),
|
|
+ sizeof(int));
|
|
+ }
|
|
+ size_t url_string_offset() const {
|
|
+ size_t offset = shared_class_file_offset();
|
|
+ if (_shared_class_file != NULL) {
|
|
+ return align_up(offset + _shared_class_file->obj_size(), sizeof(int));
|
|
+ }
|
|
+ return offset;
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
public:
|
|
CrcInfo* crc() const {
|
|
assert(crc_size(_klass) > 0, "must be");
|
|
@@ -588,6 +728,23 @@ public:
|
|
return loader_constraints() + i;
|
|
}
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ RTSharedData* shared_class_file() {
|
|
+ return (RTSharedData*)(address(this) + shared_class_file_offset());
|
|
+ }
|
|
+ RTSharedData* url_string() {
|
|
+ return (RTSharedData*)(address(this) + url_string_offset());
|
|
+ }
|
|
+
|
|
+ int64_t classfile_timestamp() {
|
|
+ return _classfile_timestamp;
|
|
+ }
|
|
+
|
|
+ void set_classfile_timestamp(int64_t classfile_timestamp) {
|
|
+ _classfile_timestamp = classfile_timestamp;
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
void init(DumpTimeSharedClassInfo& info) {
|
|
ArchiveBuilder* builder = ArchiveBuilder::current();
|
|
assert(builder->is_in_buffer_space(info._klass), "must be");
|
|
@@ -625,6 +782,28 @@ public:
|
|
InstanceKlass* n_h = info.nest_host();
|
|
set_nest_host(n_h);
|
|
}
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (info.shared_class_file_size() != 0) {
|
|
+ assert(_url_string == NULL, "must assigned before _url_string");
|
|
+ _shared_class_file = shared_class_file();
|
|
+ memcpy(_shared_class_file, info.shared_class_file(), info.shared_class_file_size());
|
|
+ ArchivePtrMarker::mark_pointer(&_shared_class_file);
|
|
+ info.free_shared_class_file();
|
|
+ } else {
|
|
+ _shared_class_file = NULL;
|
|
+ }
|
|
+ if (info.url_string_size() != 0) {
|
|
+ _url_string = url_string();
|
|
+ memcpy(_url_string, info.url_string(), info.url_string_size());
|
|
+ ArchivePtrMarker::mark_pointer(&_url_string);
|
|
+ info.free_url_string();
|
|
+ } else {
|
|
+ _url_string = NULL;
|
|
+ }
|
|
+ set_classfile_timestamp(info.classfile_timestamp());
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
ArchivePtrMarker::mark_pointer(&_klass);
|
|
}
|
|
|
|
@@ -668,6 +847,77 @@ public:
|
|
const RunTimeSharedClassInfo* value, Symbol* key, int len_unused) {
|
|
return (value->_klass->name() == key);
|
|
}
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ ClassFileStream* get_shared_class_file_stream() {
|
|
+ if (_shared_class_file != NULL) {
|
|
+ return new ClassFileStream(_shared_class_file->data,
|
|
+ _shared_class_file->length,
|
|
+ "__VM_AggressiveCDS__",
|
|
+ ClassFileStream::verify);
|
|
+ }
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+
|
|
+ // check timestamp in the load time when UseAggressiveCDS.
|
|
+ // regular_file(*.class): need to check timestamp.
|
|
+ // jar_file(*.jar): no need to check timestamp here,already checked
|
|
+ // somewhere else, see SharedClassPathEntry::validate.
|
|
+ // other_file: not supported when UseAggressiveCDS.
|
|
+ bool check_classfile_timestamp(char* url_string, TRAPS) {
|
|
+ if (SystemDictionaryShared::is_regular_file(url_string)) {
|
|
+ ResourceMark rm(THREAD);
|
|
+ char* dir = SystemDictionaryShared::get_filedir(url_string);
|
|
+ if (dir == NULL) {
|
|
+ return false;
|
|
+ }
|
|
+ int64_t timestamp = SystemDictionaryShared::get_timestamp(dir, _klass->name());
|
|
+ if (timestamp != _classfile_timestamp) {
|
|
+ log_trace(cds, aggressive)("%s, timestamp mismatch: " INT64_FORMAT " -> " INT64_FORMAT,
|
|
+ _klass->name()->as_C_string(),
|
|
+ _classfile_timestamp, timestamp);
|
|
+ return false;
|
|
+ }
|
|
+ } else if (!SystemDictionaryShared::is_jar_file(url_string)) {
|
|
+ log_trace(cds, aggressive)("Unsupported URL:%s", url_string);
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ Handle get_protection_domain(Handle class_loader, TRAPS) {
|
|
+ if (_url_string == NULL) {
|
|
+ return Handle();
|
|
+ }
|
|
+ char* data_ptr = (char*)(_url_string->data);
|
|
+
|
|
+ if (CheckClassFileTimeStamp) {
|
|
+ if (!check_classfile_timestamp(data_ptr, THREAD)) {
|
|
+ return Handle();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ Handle url_string = java_lang_String::create_from_str(data_ptr, THREAD);
|
|
+ JavaValue result(T_OBJECT);
|
|
+ JavaCalls::call_virtual(&result,
|
|
+ class_loader,
|
|
+ class_loader->klass(),
|
|
+ vmSymbols::getProtectionDomainByURLString_name(),
|
|
+ vmSymbols::getProtectionDomainByURLString_signature(),
|
|
+ url_string, THREAD);
|
|
+ if (!HAS_PENDING_EXCEPTION) {
|
|
+ return Handle(THREAD, result.get_oop());
|
|
+ } else {
|
|
+ LogTarget(Warning, cds, aggressive) lt;
|
|
+ if (lt.is_enabled()) {
|
|
+ lt.print("Unknown exception in get_protection_domain():");
|
|
+ }
|
|
+ DebugUtils::clear_java_exception_and_print_stack_trace(lt, THREAD);
|
|
+ }
|
|
+ return Handle();
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
};
|
|
|
|
class RunTimeSharedDictionary : public OffsetCompactHashtable<
|
|
@@ -2036,7 +2286,11 @@ public:
|
|
|
|
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
|
if (!info.is_excluded()) {
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ size_t byte_size = RunTimeSharedClassInfo::byte_size(info);
|
|
+#else
|
|
size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_verifier_constraints(), info.num_loader_constraints());
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
_shared_class_info_size += align_up(byte_size, SharedSpaceObjectAlignment);
|
|
}
|
|
return true; // keep on iterating
|
|
@@ -2095,6 +2349,17 @@ public:
|
|
// if (SystemDictionaryShared::is_excluded_class(info._proxy_klasses->at(0))) {
|
|
// return true;
|
|
//}
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ // In Dynamic dump, info is from _dumptime_lambda_proxy_class_dictionary, which is created by
|
|
+ // runtime JNI call, see Java_java_lang_invoke_LambdaProxyClassArchive_addToArchive.
|
|
+ // check_excluded_classes can't exclude DumpTimeLambdaProxyClassInfo, check excluded here
|
|
+ if (UseAggressiveCDS && DynamicDumpSharedSpaces
|
|
+ && SystemDictionaryShared::is_excluded_class(info._proxy_klasses->at(0))) {
|
|
+ return true;
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
ResourceMark rm;
|
|
log_info(cds,dynamic)("Archiving hidden %s", info._proxy_klasses->at(0)->external_name());
|
|
size_t byte_size = sizeof(RunTimeLambdaProxyClassInfo);
|
|
@@ -2112,6 +2377,12 @@ class AdjustLambdaProxyClassInfo : StackObj {
|
|
public:
|
|
AdjustLambdaProxyClassInfo() {}
|
|
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (UseAggressiveCDS && DynamicDumpSharedSpaces
|
|
+ && SystemDictionaryShared::is_excluded_class(info._proxy_klasses->at(0))) {
|
|
+ return true;
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
int len = info._proxy_klasses->length();
|
|
if (len > 1) {
|
|
for (int i = 0; i < len-1; i++) {
|
|
@@ -2134,6 +2405,39 @@ public:
|
|
}
|
|
};
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+class ExcludeDuplicateKlass : StackObj {
|
|
+public:
|
|
+ static const int INITIAL_TABLE_SIZE = 15889;
|
|
+
|
|
+ ExcludeDuplicateKlass(int size) : _has_been_visited(size) {}
|
|
+
|
|
+ bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
|
+ if (!info.is_excluded()) {
|
|
+ bool created;
|
|
+ Symbol* name = info._klass->name();
|
|
+ address* info_ptr = _has_been_visited.add_if_absent((address)name, (address)&info, &created);
|
|
+ if (!created) {
|
|
+ info.set_excluded();
|
|
+ DumpTimeSharedClassInfo* first_info = (DumpTimeSharedClassInfo*)(*info_ptr);
|
|
+ if (!first_info->is_excluded()) {
|
|
+ first_info->set_excluded();
|
|
+ }
|
|
+ LogTarget(Trace, cds, aggressive) lt;
|
|
+ if (lt.is_enabled()) {
|
|
+ ResourceMark rm;
|
|
+ lt.print("Skipping duplicate class (excluded): %s", name->as_C_string());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+private:
|
|
+ ScalarHashMap<address, address, mtClassShared> _has_been_visited;
|
|
+};
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
class CopySharedClassInfoToArchive : StackObj {
|
|
CompactHashtableWriter* _writer;
|
|
bool _is_builtin;
|
|
@@ -2145,7 +2449,11 @@ public:
|
|
|
|
bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
|
|
if (!info.is_excluded() && info.is_builtin() == _is_builtin) {
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ size_t byte_size = RunTimeSharedClassInfo::byte_size(info);
|
|
+#else
|
|
size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_verifier_constraints(), info.num_loader_constraints());
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
RunTimeSharedClassInfo* record;
|
|
record = (RunTimeSharedClassInfo*)ArchiveBuilder::ro_region_alloc(byte_size);
|
|
record->init(info);
|
|
@@ -2184,6 +2492,12 @@ void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionar
|
|
bool is_builtin) {
|
|
CompactHashtableStats stats;
|
|
dictionary->reset();
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ if (UseAggressiveCDS && !is_builtin) {
|
|
+ ExcludeDuplicateKlass dup(ExcludeDuplicateKlass::INITIAL_TABLE_SIZE);
|
|
+ _dumptime_table->iterate(&dup);
|
|
+ }
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
CompactHashtableWriter writer(_dumptime_table->count_of(is_builtin), &stats);
|
|
CopySharedClassInfoToArchive copy(&writer, is_builtin);
|
|
assert_lock_strong(DumpTimeTable_lock);
|
|
@@ -2493,4 +2807,210 @@ void SystemDictionaryShared::update_archived_mirror_native_pointers() {
|
|
ArchivedMirrorPatcher::update_array_klasses(k);
|
|
}
|
|
}
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ClassFileStream* SystemDictionaryShared::get_shared_class_file_stream(InstanceKlass* k) {
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+ RunTimeSharedClassInfo* info = RunTimeSharedClassInfo::get_for(k);
|
|
+ return info->get_shared_class_file_stream();
|
|
+}
|
|
+
|
|
+ClassFileStream* SystemDictionaryShared::get_byte_code_from_cache(Symbol* class_name, Handle class_loader, TRAPS) {
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+
|
|
+ TempNewSymbol plugin_name = SymbolTable::new_symbol("java/net/AggressiveCDSPlugin");
|
|
+ InstanceKlass* plugin_klass = SystemDictionary::find_instance_klass(plugin_name, Handle(), Handle());
|
|
+ assert(plugin_klass != NULL, "sanity");
|
|
+ JavaValue result(T_OBJECT);
|
|
+ Handle name = java_lang_String::create_from_symbol(class_name, CHECK_NULL);
|
|
+ TempNewSymbol method_name = SymbolTable::new_symbol("getByteCodeFromCache");
|
|
+ TempNewSymbol method_signature = SymbolTable::new_symbol("(Ljava/net/URLClassLoader;Ljava/lang/String;)[B");
|
|
+
|
|
+ JavaCalls::call_static(&result,
|
|
+ plugin_klass,
|
|
+ method_name,
|
|
+ method_signature,
|
|
+ class_loader,
|
|
+ name,
|
|
+ CHECK_NULL);
|
|
+
|
|
+ typeArrayHandle res_h(THREAD, (typeArrayOop) result.get_oop());
|
|
+ if (res_h.is_null()) {
|
|
+ return NULL;
|
|
+ }
|
|
+ int len = res_h->length();
|
|
+ u1* buf = NEW_RESOURCE_ARRAY(u1, len);
|
|
+ memcpy(buf, (u1*) res_h->byte_at_addr(0), len);
|
|
+ return new ClassFileStream(buf, len, "__VM_AggressiveCDS__", ClassFileStream::verify);
|
|
+}
|
|
+
|
|
+void SystemDictionaryShared::set_shared_class_file(InstanceKlass* k, ClassFileStream* cfs) {
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+ Arguments::assert_is_dumping_archive();
|
|
+ DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
|
+ if (info != NULL && info->_shared_class_file == NULL) {
|
|
+ info->copy_shared_class_file(cfs);
|
|
+ }
|
|
+}
|
|
+
|
|
+static const char* JAR_FILE_PREFIX = "jar://"; // 1: "jar://file:", 2: "jar://nested:"
|
|
+static const char* FILE_SEPARATOR = "file://";
|
|
+static const char* CLASSFILE_SUFFIX = ".class";
|
|
+
|
|
+static bool start_with(char* str, const char* prefix) {
|
|
+ if (str == NULL || prefix == NULL || strlen(str) < strlen(prefix)) {
|
|
+ return false;
|
|
+ }
|
|
+ if (strncmp(str, prefix, strlen(prefix)) == 0) {
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+bool SystemDictionaryShared::is_jar_file(char* url_string) {
|
|
+ if (start_with(url_string, JAR_FILE_PREFIX)) {
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+bool SystemDictionaryShared::is_regular_file(char* url_string) {
|
|
+ if (start_with(url_string, FILE_SEPARATOR)) {
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+char* SystemDictionaryShared::get_filedir(char* url_string) {
|
|
+ if (!is_regular_file(url_string)) {
|
|
+ return NULL;
|
|
+ }
|
|
+ char* dir = url_string + strlen(FILE_SEPARATOR);
|
|
+ struct stat st;
|
|
+ if (os::stat(dir, &st) == 0) {
|
|
+ if ((st.st_mode & S_IFDIR) == S_IFDIR) {
|
|
+ return dir;
|
|
+ }
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+int64_t SystemDictionaryShared::get_timestamp(char* dir, Symbol* class_name) {
|
|
+ char* name = class_name->as_C_string();
|
|
+ size_t name_len = strlen(name);
|
|
+ size_t dir_len = strlen(dir);
|
|
+ size_t classfile_suffix_len = strlen(CLASSFILE_SUFFIX);
|
|
+ char* file_path = NEW_RESOURCE_ARRAY(char, dir_len + name_len + classfile_suffix_len + 1);
|
|
+ memcpy(file_path, dir, dir_len);
|
|
+ memcpy(file_path + dir_len, name, name_len);
|
|
+ memcpy(file_path + dir_len + name_len, CLASSFILE_SUFFIX, classfile_suffix_len + 1);
|
|
+ assert(strlen(file_path) == dir_len + name_len + classfile_suffix_len, "sanity");
|
|
+ struct stat st;
|
|
+ if (os::stat(file_path, &st) == 0) {
|
|
+ return st.st_mtime;
|
|
+ }
|
|
+ log_trace(cds, aggressive)("get timestamp failed:%s", file_path);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+Handle SystemDictionaryShared::get_protection_domain(InstanceKlass* k, Handle class_loader, TRAPS) {
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+ RunTimeSharedClassInfo* info = RunTimeSharedClassInfo::get_for(k);
|
|
+ return info->get_protection_domain(class_loader, CHECK_NH);
|
|
+}
|
|
+
|
|
+void SystemDictionaryShared::set_url_string(InstanceKlass* k, char* string_value) {
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+ Arguments::assert_is_dumping_archive();
|
|
+ DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
|
+ if (info != NULL && info->_url_string == NULL) {
|
|
+ info->copy_url_string(string_value);
|
|
+ }
|
|
+}
|
|
+
|
|
+void SystemDictionaryShared::save_timestamp(InstanceKlass* k, char* string_value) {
|
|
+ if (SystemDictionaryShared::is_regular_file(string_value)) {
|
|
+ char* dir = SystemDictionaryShared::get_filedir(string_value);
|
|
+ if (dir != NULL) {
|
|
+ int64_t timestamp = SystemDictionaryShared::get_timestamp(dir, k->name());
|
|
+ SystemDictionaryShared::set_classfile_timestamp(k, timestamp);
|
|
+ } else {
|
|
+ log_trace(cds, aggressive)("Unsupported URL:%s", string_value);
|
|
+ }
|
|
+ } else if (!SystemDictionaryShared::is_jar_file(string_value)) {
|
|
+ log_trace(cds, aggressive)("Unsupported URL:%s", string_value);
|
|
+ }
|
|
+}
|
|
+
|
|
+void SystemDictionaryShared::set_classfile_timestamp(InstanceKlass* k, int64_t classfile_timestamp) {
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+ Arguments::assert_is_dumping_archive();
|
|
+ DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
|
|
+ if (info != NULL) {
|
|
+ info->set_classfile_timestamp(classfile_timestamp);
|
|
+ }
|
|
+}
|
|
+
|
|
+InstanceKlass* SystemDictionaryShared::lookup_trusted_share_class(Symbol* class_name,
|
|
+ Handle class_loader,
|
|
+ TRAPS) {
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+ if (!UseSharedSpaces) {
|
|
+ return NULL;
|
|
+ }
|
|
+ if (class_name == NULL) { // don't do this for hidden classes
|
|
+ return NULL;
|
|
+ }
|
|
+ if (class_loader.is_null() ||
|
|
+ SystemDictionary::is_system_class_loader(class_loader()) ||
|
|
+ SystemDictionary::is_platform_class_loader(class_loader())) {
|
|
+ // Do nothing for the BUILTIN loaders.
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ // We may want to inject some code into the klass.
|
|
+ // So do not load the klass from jsa.
|
|
+ if (UseJBooster && JBoosterStartupSignal != nullptr) {
|
|
+ if (ClientStartupSignal::is_target_klass(class_name)) {
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ Handle lock = get_loader_lock_or_null(class_loader);
|
|
+ ObjectLocker ol(lock, THREAD);
|
|
+
|
|
+ register_loader(class_loader);
|
|
+
|
|
+ if (log_is_enabled(Info, cds)) {
|
|
+ ResourceMark rm(THREAD);
|
|
+ log_info(cds)("lookup_trusted_share_class %s: %s", class_name->as_C_string(),
|
|
+ class_loader()->klass()->name()->as_C_string());
|
|
+ }
|
|
+
|
|
+ const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary,
|
|
+ &_dynamic_unregistered_dictionary,
|
|
+ class_name);
|
|
+ if (record == NULL) {
|
|
+ log_info(cds)("not find class name : %s ", class_name->as_C_string());
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ Handle protection_domain = SystemDictionaryShared::get_protection_domain(record->_klass, class_loader, CHECK_NULL);
|
|
+ if (protection_domain.is_null()) {
|
|
+ // The protection_domain is rebuilt based on the RunTimeSharedClassInfo::_url_string.
|
|
+ // We lookup the URL of _url_string from the URLClassPath of the URLClassLoader.
|
|
+ // The URLClassPath returns null if _url_string is not in its url array, which also
|
|
+ // means that this class was not defined by this class loader at dump run.
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ InstanceKlass* k = acquire_class_for_current_thread(record->_klass, class_loader, protection_domain, NULL, THREAD);
|
|
+ if (k != NULL) {
|
|
+ SharedClassLoadingMark slm(THREAD, k);
|
|
+ find_or_define_instance_class(class_name, class_loader, k, CHECK_NULL);
|
|
+ }
|
|
+ return k;
|
|
+}
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
#endif
|
|
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp
|
|
index 5ba59378e..6dafba669 100644
|
|
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp
|
|
+++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp
|
|
@@ -376,6 +376,23 @@ private:
|
|
public:
|
|
static void update_archived_mirror_native_pointers() NOT_CDS_RETURN;
|
|
#endif
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ static bool is_jar_file(char* url_string);
|
|
+ static bool is_regular_file(char* url_string);
|
|
+ static char* get_filedir(char* url_string);
|
|
+ static int64_t get_timestamp(char* dir, Symbol* class_name);
|
|
+ static ClassFileStream* get_shared_class_file_stream(InstanceKlass* k);
|
|
+ static ClassFileStream* get_byte_code_from_cache(Symbol* class_name, Handle class_loader, TRAPS);
|
|
+ static void set_shared_class_file(InstanceKlass* k, ClassFileStream* cfs);
|
|
+ static Handle get_protection_domain(InstanceKlass* k, Handle class_loader, TRAPS);
|
|
+ static void set_url_string(InstanceKlass* k, char* string_value);
|
|
+ static void save_timestamp(InstanceKlass* k, char* string_value);
|
|
+ static void set_classfile_timestamp(InstanceKlass* k, int64_t classfile_timestamp);
|
|
+ static int64_t get_classfile_timestamp(InstanceKlass* k);
|
|
+
|
|
+ static InstanceKlass* lookup_trusted_share_class(Symbol* class_name, Handle class_loader, TRAPS);
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
};
|
|
|
|
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
|
|
diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h
|
|
index ee821eb73..784d3026a 100644
|
|
--- a/src/hotspot/share/include/cds.h
|
|
+++ b/src/hotspot/share/include/cds.h
|
|
@@ -35,6 +35,7 @@
|
|
|
|
#define NUM_CDS_REGIONS 7 // this must be the same as MetaspaceShared::n_regions
|
|
#define CDS_ARCHIVE_MAGIC 0xf00baba2
|
|
+#define CDS_AGGRESSIVE_ARCHIVE_MAGIC 0xf00baba4
|
|
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
|
|
#define CURRENT_CDS_ARCHIVE_VERSION 11
|
|
#define INVALID_CDS_ARCHIVE_VERSION -1
|
|
diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h
|
|
index 0f6fba8ba..4cdc9cfb6 100644
|
|
--- a/src/hotspot/share/include/jvm.h
|
|
+++ b/src/hotspot/share/include/jvm.h
|
|
@@ -1131,6 +1131,11 @@ JVM_JBoosterGetMetaspaceMethodData(JNIEnv *env, jint session_id, jlong metaspace
|
|
JNIEXPORT void JNICALL
|
|
JVM_JBoosterStartupNativeCallback(JNIEnv *env);
|
|
|
|
+/**
|
|
+ * Define the trusted shared class.
|
|
+ */
|
|
+JNIEXPORT jclass JNICALL
|
|
+JVM_DefineTrustedSharedClass(JNIEnv *env, const char *name, jobject loader);
|
|
|
|
/*
|
|
* This structure is used by the launcher to get the default thread
|
|
diff --git a/src/hotspot/share/jbooster/client/clientDataManager.cpp b/src/hotspot/share/jbooster/client/clientDataManager.cpp
|
|
index 1e4c8f2b5..55b7d2a82 100644
|
|
--- a/src/hotspot/share/jbooster/client/clientDataManager.cpp
|
|
+++ b/src/hotspot/share/jbooster/client/clientDataManager.cpp
|
|
@@ -140,6 +140,42 @@ jint ClientDataManager::init_clr_options() {
|
|
|
|
jint ClientDataManager::init_cds_options() {
|
|
if (!is_cds_allowed()) return JNI_OK;
|
|
+
|
|
+ if (FLAG_IS_CMDLINE(SharedArchiveFile) || FLAG_IS_CMDLINE(ArchiveClassesAtExit)) {
|
|
+ vm_exit_during_initialization("Do not set CDS manually whe using JBooster.");
|
|
+ }
|
|
+
|
|
+ if (is_cds_being_used()) {
|
|
+ if (FLAG_SET_CMDLINE(SharedArchiveFile, cache_cds_path()) != JVMFlag::SUCCESS) {
|
|
+ return JNI_EINVAL;
|
|
+ }
|
|
+
|
|
+ if (FLAG_SET_CMDLINE(RequireSharedSpaces, JBoosterExitIfUnsupported) != JVMFlag::SUCCESS) {
|
|
+ return JNI_EINVAL;
|
|
+ }
|
|
+ } else if (is_server_available()) {
|
|
+ // Dump data to the tmp file to prevent other processes from reading the
|
|
+ // cache file that is not completely written.
|
|
+ const char* cds_tmp_path = JBoosterManager::calc_tmp_cache_path(cache_cds_path());
|
|
+ if (FLAG_SET_CMDLINE(ArchiveClassesAtExit, cds_tmp_path) != JVMFlag::SUCCESS) {
|
|
+ return JNI_EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // It's OK to Use traditional Dynamic CDS if the user manually
|
|
+ // set UseAggressiveCDS to false.
|
|
+ if (FLAG_IS_DEFAULT(UseAggressiveCDS)) {
|
|
+ if (FLAG_SET_CMDLINE(UseAggressiveCDS, true) != JVMFlag::SUCCESS) {
|
|
+ return JNI_EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (Arguments::init_agents_at_startup()) {
|
|
+ if (FLAG_SET_CMDLINE(AllowArchivingWithJavaAgent, true) != JVMFlag::SUCCESS) {
|
|
+ return JNI_EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
return JNI_OK;
|
|
}
|
|
|
|
diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp
|
|
index 8bcdd16a7..8ac082bf1 100644
|
|
--- a/src/hotspot/share/logging/logTag.hpp
|
|
+++ b/src/hotspot/share/logging/logTag.hpp
|
|
@@ -34,6 +34,7 @@
|
|
#define LOG_TAG_LIST \
|
|
LOG_TAG(add) \
|
|
LOG_TAG(age) \
|
|
+ AGGRESSIVE_CDS_ONLY(LOG_TAG(aggressive)) \
|
|
LOG_TAG(alloc) \
|
|
LOG_TAG(annotation) \
|
|
AOT_ONLY(LOG_TAG(aot)) \
|
|
diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp
|
|
index 0d501e494..bafbfe08d 100644
|
|
--- a/src/hotspot/share/prims/jvm.cpp
|
|
+++ b/src/hotspot/share/prims/jvm.cpp
|
|
@@ -3900,4 +3900,25 @@ JVM_ENTRY(void, JVM_JBoosterStartupNativeCallback(JNIEnv *env))
|
|
ClientMessageHandler::trigger_cache_generation_tasks(ClientMessageHandler::TriggerTaskPhase::ON_STARTUP, THREAD);
|
|
log_debug(jbooster, start)("End of the startup callback.");
|
|
#endif // INCLUDE_JBOOSTER
|
|
-JVM_END
|
|
\ No newline at end of file
|
|
+JVM_END
|
|
+
|
|
+JVM_ENTRY(jclass, JVM_DefineTrustedSharedClass(JNIEnv *env, const char *name, jobject loader))
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ assert(UseAggressiveCDS, "sanity");
|
|
+ TempNewSymbol class_name = name == NULL ? NULL :
|
|
+ SystemDictionary::class_name_symbol(name,
|
|
+ vmSymbols::java_lang_NoClassDefFoundError(),
|
|
+ CHECK_NULL);
|
|
+ Handle class_loader (THREAD, JNIHandles::resolve(loader));
|
|
+ InstanceKlass* k = SystemDictionaryShared::lookup_trusted_share_class(class_name,
|
|
+ class_loader,
|
|
+ CHECK_NULL);
|
|
+ if (k == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return (jclass) JNIHandles::make_local(THREAD, k->java_mirror());
|
|
+#else
|
|
+ return NULL;
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+JVM_END
|
|
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
|
|
index 406434ab2..6a432ed6b 100644
|
|
--- a/src/hotspot/share/runtime/arguments.cpp
|
|
+++ b/src/hotspot/share/runtime/arguments.cpp
|
|
@@ -4034,6 +4034,11 @@ jint Arguments::apply_ergo() {
|
|
result = set_shared_spaces_flags_and_archive_paths();
|
|
if (result != JNI_OK) return result;
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ result = init_aggressive_cds_properties();
|
|
+ if (result != JNI_OK) return result;
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
// Initialize Metaspace flags and alignments
|
|
Metaspace::ergo_initialize();
|
|
|
|
@@ -4385,4 +4390,17 @@ jint Arguments::init_jbooster_startup_signal_properties(const char* klass_name,
|
|
return JNI_OK;
|
|
}
|
|
|
|
-#endif // INCLUDE_JBOOSTER
|
|
\ No newline at end of file
|
|
+#endif // INCLUDE_JBOOSTER
|
|
+
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
+jint Arguments::init_aggressive_cds_properties() {
|
|
+ if (!is_dumping_archive() && SharedDynamicArchivePath != NULL && UseAggressiveCDS) {
|
|
+ bool added = false;
|
|
+ added = add_property("jdk.jbooster.aggressivecds.load=true", UnwriteableProperty, InternalProperty);
|
|
+ if (!added) return JNI_ENOMEM;
|
|
+ }
|
|
+ return JNI_OK;
|
|
+}
|
|
+
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp
|
|
index 7f52419a5..a66cc0f4d 100644
|
|
--- a/src/hotspot/share/runtime/arguments.hpp
|
|
+++ b/src/hotspot/share/runtime/arguments.hpp
|
|
@@ -647,6 +647,10 @@ class Arguments : AllStatic {
|
|
const char* method_signature);
|
|
#endif // INCLUDE_JBOOSTER
|
|
|
|
+#if INCLUDE_AGGRESSIVE_CDS
|
|
+ static jint init_aggressive_cds_properties();
|
|
+#endif // INCLUDE_AGGRESSIVE_CDS
|
|
+
|
|
DEBUG_ONLY(static bool verify_special_jvm_flags(bool check_globals);)
|
|
};
|
|
|
|
diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp
|
|
index e27a135fc..f57a95533 100644
|
|
--- a/src/hotspot/share/runtime/java.cpp
|
|
+++ b/src/hotspot/share/runtime/java.cpp
|
|
@@ -94,6 +94,7 @@
|
|
#include "jfr/jfr.hpp"
|
|
#endif
|
|
#if INCLUDE_JBOOSTER
|
|
+#include "jbooster/client/clientDataManager.hpp"
|
|
#include "jbooster/client/clientMessageHandler.hpp"
|
|
#endif // INCLUDE_JBOOSTER
|
|
#if INCLUDE_AOT
|
|
@@ -522,7 +523,7 @@ void before_exit(JavaThread* thread, bool halt) {
|
|
os::terminate_signal_thread();
|
|
|
|
#if INCLUDE_CDS
|
|
- if (DynamicDumpSharedSpaces JBOOSTER_ONLY(&& !UseJBooster)) {
|
|
+ if (DynamicDumpSharedSpaces JBOOSTER_ONLY(&& !(UseJBooster && ClientDataManager::get().is_cds_allowed()))) {
|
|
ExceptionMark em(thread);
|
|
DynamicArchive::dump();
|
|
if (thread->has_pending_exception()) {
|
|
diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp
|
|
index 6f8cc606f..c25da52ed 100644
|
|
--- a/src/hotspot/share/utilities/macros.hpp
|
|
+++ b/src/hotspot/share/utilities/macros.hpp
|
|
@@ -129,6 +129,14 @@
|
|
#define JBOOSTER_ONLY(x)
|
|
#endif // INCLUDE_JBOOSTER
|
|
|
|
+#if INCLUDE_JBOOSTER && INCLUDE_CDS
|
|
+#define INCLUDE_AGGRESSIVE_CDS 1
|
|
+#define AGGRESSIVE_CDS_ONLY(x) x
|
|
+#else
|
|
+#define INCLUDE_AGGRESSIVE_CDS 0
|
|
+#define AGGRESSIVE_CDS_ONLY(x)
|
|
+#endif // INCLUDE_JBOOSTER && INCLUDE_CDS
|
|
+
|
|
#ifndef INCLUDE_MANAGEMENT
|
|
#define INCLUDE_MANAGEMENT 1
|
|
#endif // INCLUDE_MANAGEMENT
|
|
diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java
|
|
index c1caeb18c..64aca03ee 100644
|
|
--- a/src/java.base/share/classes/java/lang/ClassLoader.java
|
|
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java
|
|
@@ -930,6 +930,21 @@ public abstract class ClassLoader {
|
|
}
|
|
}
|
|
|
|
+ /**
|
|
+ * Determine protection domain, and check it.
|
|
+ * This method is only for AggressiveCDS.
|
|
+ *
|
|
+ * @param name the name of the class
|
|
+ * @param c the class
|
|
+ * @param pd the ProtectionDomain of the class
|
|
+ */
|
|
+ protected void defineClassProtectionDomain(String name, Class<?> c, ProtectionDomain pd)
|
|
+ {
|
|
+ // Determine protection domain
|
|
+ pd = preDefineClass(name, pd);
|
|
+ postDefineClass(c, pd);
|
|
+ }
|
|
+
|
|
/**
|
|
* Converts an array of bytes into an instance of class {@code Class},
|
|
* with a given {@code ProtectionDomain}.
|
|
@@ -1117,6 +1132,11 @@ public abstract class ClassLoader {
|
|
int off, int len, ProtectionDomain pd,
|
|
String source);
|
|
|
|
+ /**
|
|
+ * This method is only invoked in java.net.AggressiveCDSPlugin.
|
|
+ */
|
|
+ private static native Class<?> defineClass3(ClassLoader loader, String name);
|
|
+
|
|
/**
|
|
* Defines a class of the given flags via Lookup.defineClass.
|
|
*
|
|
diff --git a/src/java.base/share/classes/java/net/AggressiveCDSPlugin.java b/src/java.base/share/classes/java/net/AggressiveCDSPlugin.java
|
|
new file mode 100644
|
|
index 000000000..b9fcc630c
|
|
--- /dev/null
|
|
+++ b/src/java.base/share/classes/java/net/AggressiveCDSPlugin.java
|
|
@@ -0,0 +1,203 @@
|
|
+/*
|
|
+ * Copyright (c) 2020, 2023, 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 java.net;
|
|
+
|
|
+import jdk.internal.loader.Resource;
|
|
+import jdk.internal.loader.URLClassPath;
|
|
+
|
|
+import java.io.IOException;
|
|
+import java.io.InputStream;
|
|
+import java.lang.invoke.MethodHandle;
|
|
+import java.lang.invoke.MethodHandles;
|
|
+import java.lang.reflect.Method;
|
|
+
|
|
+import sun.security.action.GetBooleanAction;
|
|
+
|
|
+/**
|
|
+ * The Aggressive CDS plugin for {@link java.net.URLClassLoader}.
|
|
+ */
|
|
+final class AggressiveCDSPlugin {
|
|
+ private static final boolean IS_ENABLED = GetBooleanAction.privilegedGetProperty("jdk.jbooster.aggressivecds.load");
|
|
+
|
|
+ /**
|
|
+ * Check whether Aggressive CDS is enabled.
|
|
+ *
|
|
+ * @return Is Aggressive CDS enabled
|
|
+ */
|
|
+ public static boolean isEnabled() {
|
|
+ return IS_ENABLED;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Define the class by Aggressive CDS. The class is trusted and shared,
|
|
+ *
|
|
+ * @param loader The class loader of the class (should be URLClassLoader)
|
|
+ * @param name The name of the class
|
|
+ * @return The defined class, or null if not found
|
|
+ */
|
|
+ public static Class<?> defineTrustedSharedClass(URLClassLoader loader, String name) {
|
|
+ return ClassLoaderUtil.defineClass3(loader, name);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * get URL from URLClassPath by Aggressive CDS.
|
|
+ *
|
|
+ * @param ucp The URLClassPath
|
|
+ * @param urlNoFragString The name string of the url
|
|
+ * @return The URL, or null if not found
|
|
+ */
|
|
+ public static URL getURLFromURLClassPath(URLClassPath ucp, String urlNoFragString) {
|
|
+ return URLClassPathTool.getURL(ucp, urlNoFragString);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Finds the byte code with the specified name on the URL search path.
|
|
+ * This method is invoked only in C++ ({@code SystemDictionaryShared::get_byte_code_from_cache}).
|
|
+ *
|
|
+ * @param loader The class loader of the class
|
|
+ * @param name The name of the class
|
|
+ * @return Byte code of the resource, or {@code null} if not found
|
|
+ * @throws IOException Resource.getBytes()
|
|
+ */
|
|
+ private static byte[] getByteCodeFromCache(URLClassLoader loader, String name) throws IOException {
|
|
+ String path = name.replace('.', '/').concat(".class");
|
|
+ Resource resource = getResourceFromCache(loader, path);
|
|
+ if (resource == null) {
|
|
+ return null;
|
|
+ } else {
|
|
+ return resource.getBytes();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Finds the byte code with the specified name on the URL search path.
|
|
+ * This method is invoked only in C++.
|
|
+ *
|
|
+ * @param loader The class loader of the class
|
|
+ * @param name The name of the class
|
|
+ * @return The resource in cache
|
|
+ */
|
|
+ private static Resource getResourceFromCache(URLClassLoader loader, final String name) {
|
|
+ URL url = loader.findResource(name);
|
|
+ if (url == null) {
|
|
+ return null;
|
|
+ }
|
|
+ final URLConnection uc;
|
|
+ try {
|
|
+ uc = url.openConnection();
|
|
+ } catch (IOException e) {
|
|
+ return null;
|
|
+ }
|
|
+ return new Resource() {
|
|
+ @Override
|
|
+ public String getName() {
|
|
+ return name;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public URL getURL() {
|
|
+ return url;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public URL getCodeSourceURL() {
|
|
+ return url;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public InputStream getInputStream() throws IOException {
|
|
+ return uc.getInputStream();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getContentLength() throws IOException {
|
|
+ return uc.getContentLength();
|
|
+ }
|
|
+ };
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * We don't want to add new public methods in {@link java.lang.ClassLoader}. So we add
|
|
+ * a private method (defineClass3) and use a method handle to invoke it.
|
|
+ */
|
|
+final class ClassLoaderUtil {
|
|
+ private static final MethodHandle classDefiner3;
|
|
+
|
|
+ static {
|
|
+ MethodHandle mh3 = null;
|
|
+ try {
|
|
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
|
|
+ Method m3 = ClassLoader.class.getDeclaredMethod("defineClass3", ClassLoader.class, String.class);
|
|
+ m3.setAccessible(true);
|
|
+ mh3 = lookup.unreflect(m3);
|
|
+ } catch (NoSuchMethodException | IllegalAccessException e) {
|
|
+ e.printStackTrace();
|
|
+ System.exit(1);
|
|
+ }
|
|
+ classDefiner3 = mh3;
|
|
+ }
|
|
+
|
|
+ public static Class<?> defineClass3(ClassLoader loader, String name) {
|
|
+ try {
|
|
+ return (Class<?>) classDefiner3.invoke(loader, name);
|
|
+ } catch (Throwable throwable) {
|
|
+ throwable.printStackTrace();
|
|
+ System.exit(1);
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * We don't want to add new public methods in {@link jdk.internal.loader.URLClassPath}. So we add
|
|
+ * a private method (getURL) and use a method handle to invoke it.
|
|
+ */
|
|
+final class URLClassPathTool {
|
|
+ private static final MethodHandle getURLMethodHandle;
|
|
+
|
|
+ static {
|
|
+ MethodHandle getURL = null;
|
|
+ try {
|
|
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
|
|
+ Method getURLMethod = URLClassPath.class.getDeclaredMethod("getURL", String.class);
|
|
+ getURLMethod.setAccessible(true);
|
|
+ getURL = lookup.unreflect(getURLMethod);
|
|
+ } catch (NoSuchMethodException | IllegalAccessException e) {
|
|
+ e.printStackTrace();
|
|
+ System.exit(1);
|
|
+ }
|
|
+ getURLMethodHandle = getURL;
|
|
+ }
|
|
+
|
|
+ public static URL getURL(URLClassPath ucp, String urlNoFragString) {
|
|
+ try {
|
|
+ return (URL) getURLMethodHandle.invoke(ucp, urlNoFragString);
|
|
+ } catch (Throwable throwable) {
|
|
+ throwable.printStackTrace();
|
|
+ System.exit(1);
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/java.base/share/classes/java/net/URLClassLoader.java b/src/java.base/share/classes/java/net/URLClassLoader.java
|
|
index 97c95bc9f..8314d5bb3 100644
|
|
--- a/src/java.base/share/classes/java/net/URLClassLoader.java
|
|
+++ b/src/java.base/share/classes/java/net/URLClassLoader.java
|
|
@@ -38,6 +38,7 @@ import java.security.Permission;
|
|
import java.security.PermissionCollection;
|
|
import java.security.PrivilegedAction;
|
|
import java.security.PrivilegedExceptionAction;
|
|
+import java.security.ProtectionDomain;
|
|
import java.security.SecureClassLoader;
|
|
import java.util.Enumeration;
|
|
import java.util.List;
|
|
@@ -420,6 +421,17 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|
result = AccessController.doPrivileged(
|
|
new PrivilegedExceptionAction<>() {
|
|
public Class<?> run() throws ClassNotFoundException {
|
|
+ if (AggressiveCDSPlugin.isEnabled()) {
|
|
+ try {
|
|
+ Class<?> trustedClass = AggressiveCDSPlugin
|
|
+ .defineTrustedSharedClass(URLClassLoader.this, name);
|
|
+ if (trustedClass != null) {
|
|
+ ProtectionDomain pd = trustedClass.getProtectionDomain();
|
|
+ defineClassProtectionDomain(name, trustedClass, pd);
|
|
+ return trustedClass;
|
|
+ }
|
|
+ } catch (Throwable ignored) {}
|
|
+ }
|
|
String path = name.replace('.', '/').concat(".class");
|
|
Resource res = ucp.getResource(path, false);
|
|
if (res != null) {
|
|
@@ -447,6 +459,24 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|
return result;
|
|
}
|
|
|
|
+ /**
|
|
+ * get ProtectionDomain By URL String.
|
|
+ * This method is invoked only in C++ for AggressiveCDS.
|
|
+ *
|
|
+ * @param urlNoFragString the URL String.
|
|
+ *
|
|
+ * @return ProtectionDomain create from URL.
|
|
+ */
|
|
+ private ProtectionDomain getProtectionDomainByURLString(String urlNoFragString) {
|
|
+ if (AggressiveCDSPlugin.isEnabled()) {
|
|
+ URL url = AggressiveCDSPlugin.getURLFromURLClassPath(ucp, urlNoFragString);
|
|
+ if (url != null) {
|
|
+ return getProtectionDomainFromURL(url);
|
|
+ }
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+
|
|
/*
|
|
* Retrieve the package using the specified package name.
|
|
* If non-null, verify the package using the specified code
|
|
diff --git a/src/java.base/share/classes/java/security/SecureClassLoader.java b/src/java.base/share/classes/java/security/SecureClassLoader.java
|
|
index 9ea5e3e50..2e0613700 100644
|
|
--- a/src/java.base/share/classes/java/security/SecureClassLoader.java
|
|
+++ b/src/java.base/share/classes/java/security/SecureClassLoader.java
|
|
@@ -25,6 +25,7 @@
|
|
|
|
package java.security;
|
|
|
|
+import java.net.URL;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
@@ -235,6 +236,19 @@ public class SecureClassLoader extends ClassLoader {
|
|
});
|
|
}
|
|
|
|
+ /**
|
|
+ * get ProtectionDomain From URL.
|
|
+ * This method is only for AggressiveCDS.
|
|
+ *
|
|
+ * @param url the URL.
|
|
+ *
|
|
+ * @return ProtectionDomain create from URL.
|
|
+ */
|
|
+ protected ProtectionDomain getProtectionDomainFromURL(URL url) {
|
|
+ CodeSource cs = new CodeSource(url, (CodeSigner[]) null);
|
|
+ return getProtectionDomain(cs);
|
|
+ }
|
|
+
|
|
private static class CodeSourceKey {
|
|
private final CodeSource cs;
|
|
|
|
diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java
|
|
index 02b961497..0cc500127 100644
|
|
--- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java
|
|
+++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java
|
|
@@ -324,6 +324,24 @@ public class URLClassPath {
|
|
return null;
|
|
}
|
|
|
|
+ /**
|
|
+ * Finds the URL which has the specified name.
|
|
+ * This method is only for AggressiveCDS.
|
|
+ *
|
|
+ * @param urlNoFragString the name of URL
|
|
+ * @return the URL, or null if not found
|
|
+ */
|
|
+ private URL getURL(String urlNoFragString) {
|
|
+ if (!unopenedUrls.isEmpty()) {
|
|
+ int index = loaders.size();
|
|
+ while(getLoader(index) != null) {
|
|
+ index++;
|
|
+ }
|
|
+ }
|
|
+ Loader loader = lmap.get(urlNoFragString);
|
|
+ return loader != null ? loader.getBaseURL() : null;
|
|
+ }
|
|
+
|
|
/**
|
|
* Finds all resources on the URL search path with the given name.
|
|
* Returns an enumeration of the URL objects.
|
|
diff --git a/src/java.base/share/native/libjava/ClassLoader.c b/src/java.base/share/native/libjava/ClassLoader.c
|
|
index bbdff87b0..cc8cb32aa 100644
|
|
--- a/src/java.base/share/native/libjava/ClassLoader.c
|
|
+++ b/src/java.base/share/native/libjava/ClassLoader.c
|
|
@@ -316,3 +316,29 @@ Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader,
|
|
return JVM_FindLoadedClass(env, loader, name);
|
|
}
|
|
}
|
|
+
|
|
+JNIEXPORT jclass JNICALL
|
|
+Java_java_lang_ClassLoader_defineClass3(JNIEnv *env,
|
|
+ jclass cls,
|
|
+ jobject loader,
|
|
+ jstring name)
|
|
+{
|
|
+ jclass result = 0;
|
|
+ char *utfName;
|
|
+ char buf[128];
|
|
+
|
|
+ if (name != NULL) {
|
|
+ utfName = getUTF(env, name, buf, sizeof(buf));
|
|
+ if (utfName == NULL) {
|
|
+ JNU_ThrowOutOfMemoryError(env, NULL);
|
|
+ return result;
|
|
+ }
|
|
+ fixClassname(utfName);
|
|
+ } else {
|
|
+ utfName = NULL;
|
|
+ }
|
|
+
|
|
+ result = JVM_DefineTrustedSharedClass(env, utfName, loader);
|
|
+
|
|
+ return result;
|
|
+}
|
|
--
|
|
2.19.1
|
|
|