mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 18:03:44 +00:00
8328313: Archived module graph should allow identical --module-path to be specified during dump time and run time
Reviewed-by: alanb, dholmes, iklam
This commit is contained in:
parent
9fc1c68442
commit
0bdfe88e4c
@ -236,7 +236,7 @@ void CDSConfig::init_shared_archive_paths() {
|
||||
}
|
||||
|
||||
void CDSConfig::check_internal_module_property(const char* key, const char* value) {
|
||||
if (Arguments::is_internal_module_property(key)) {
|
||||
if (Arguments::is_internal_module_property(key) && !Arguments::is_module_path_property(key)) {
|
||||
stop_using_optimized_module_handling();
|
||||
log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
|
||||
}
|
||||
|
||||
@ -781,12 +781,12 @@ bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, Growable
|
||||
assert(strlen(rp_array->at(i)) > (size_t)runtime_prefix_len, "sanity");
|
||||
const char* runtime_path = rp_array->at(i) + runtime_prefix_len;
|
||||
if (!os::same_files(dumptime_path, runtime_path)) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileMapInfo::validate_boot_class_paths() {
|
||||
@ -810,7 +810,7 @@ bool FileMapInfo::validate_boot_class_paths() {
|
||||
char* rp = skip_first_path_entry(runtime_boot_path);
|
||||
assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
|
||||
int dp_len = header()->app_class_paths_start_index() - 1; // ignore the first path to the module image
|
||||
bool mismatch = false;
|
||||
bool match = true;
|
||||
|
||||
bool relaxed_check = !header()->has_platform_or_app_classes();
|
||||
if (dp_len == 0 && rp == nullptr) {
|
||||
@ -823,7 +823,7 @@ bool FileMapInfo::validate_boot_class_paths() {
|
||||
if (check_paths_existence(rp)) {
|
||||
// If a path exists in the runtime boot paths, it is considered a mismatch
|
||||
// since there's no boot path specified during dump time.
|
||||
mismatch = true;
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
} else if (dp_len > 0 && rp != nullptr) {
|
||||
@ -840,16 +840,16 @@ bool FileMapInfo::validate_boot_class_paths() {
|
||||
// check the full runtime boot path, must match with dump time
|
||||
num = rp_len;
|
||||
}
|
||||
mismatch = check_paths(1, num, rp_array, 0, 0);
|
||||
match = check_paths(1, num, rp_array, 0, 0);
|
||||
} else {
|
||||
// create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths
|
||||
// are the same initially, after the call to create_path_array(), the runtime boot classpath length could become
|
||||
// shorter. We consider boot classpath mismatch in this case.
|
||||
mismatch = true;
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mismatch) {
|
||||
if (!match) {
|
||||
// The paths are different
|
||||
return classpath_failure("[BOOT classpath mismatch, actual =", runtime_boot_path);
|
||||
}
|
||||
@ -860,7 +860,7 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
|
||||
const char *appcp = Arguments::get_appclasspath();
|
||||
assert(appcp != nullptr, "null app classpath");
|
||||
int rp_len = num_paths(appcp);
|
||||
bool mismatch = false;
|
||||
bool match = false;
|
||||
if (rp_len < shared_app_paths_len) {
|
||||
return classpath_failure("Run time APP classpath is shorter than the one at dump time: ", appcp);
|
||||
}
|
||||
@ -889,8 +889,8 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
|
||||
// run 2: -cp x.jar:NE4:b.jar -> x.jar:b.jar -> mismatched
|
||||
|
||||
int j = header()->app_class_paths_start_index();
|
||||
mismatch = check_paths(j, shared_app_paths_len, rp_array, 0, 0);
|
||||
if (mismatch) {
|
||||
match = check_paths(j, shared_app_paths_len, rp_array, 0, 0);
|
||||
if (!match) {
|
||||
// To facilitate app deployment, we allow the JAR files to be moved *together* to
|
||||
// a different location, as long as they are still stored under the same directory
|
||||
// structure. E.g., the following is OK.
|
||||
@ -901,10 +901,10 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
|
||||
if (dumptime_prefix_len != 0 || runtime_prefix_len != 0) {
|
||||
log_info(class, path)("LCP length for app classpath (dumptime: %u, runtime: %u)",
|
||||
dumptime_prefix_len, runtime_prefix_len);
|
||||
mismatch = check_paths(j, shared_app_paths_len, rp_array,
|
||||
match = check_paths(j, shared_app_paths_len, rp_array,
|
||||
dumptime_prefix_len, runtime_prefix_len);
|
||||
}
|
||||
if (mismatch) {
|
||||
if (!match) {
|
||||
return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp);
|
||||
}
|
||||
}
|
||||
@ -926,15 +926,35 @@ void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) {
|
||||
}
|
||||
}
|
||||
|
||||
void FileMapInfo::extract_module_paths(const char* runtime_path, GrowableArray<const char*>* module_paths) {
|
||||
GrowableArray<const char*>* path_array = create_path_array(runtime_path);
|
||||
int num_paths = path_array->length();
|
||||
for (int i = 0; i < num_paths; i++) {
|
||||
const char* name = path_array->at(i);
|
||||
ClassLoaderExt::extract_jar_files_from_path(name, module_paths);
|
||||
}
|
||||
// module paths are stored in sorted order in the CDS archive.
|
||||
module_paths->sort(ClassLoaderExt::compare_module_path_by_name);
|
||||
}
|
||||
|
||||
bool FileMapInfo::check_module_paths() {
|
||||
const char* rp = Arguments::get_property("jdk.module.path");
|
||||
int num_paths = CDSConfig::num_archives(rp);
|
||||
if (num_paths != header()->num_module_paths()) {
|
||||
const char* runtime_path = Arguments::get_property("jdk.module.path");
|
||||
int archived_num_module_paths = header()->num_module_paths();
|
||||
if (runtime_path == nullptr && archived_num_module_paths == 0) {
|
||||
return true;
|
||||
}
|
||||
if ((runtime_path == nullptr && archived_num_module_paths > 0) ||
|
||||
(runtime_path != nullptr && archived_num_module_paths == 0)) {
|
||||
return false;
|
||||
}
|
||||
ResourceMark rm;
|
||||
GrowableArray<const char*>* rp_array = create_path_array(rp);
|
||||
return check_paths(header()->app_module_paths_start_index(), num_paths, rp_array, 0, 0);
|
||||
GrowableArray<const char*>* module_paths = new GrowableArray<const char*>(3);
|
||||
extract_module_paths(runtime_path, module_paths);
|
||||
int num_paths = module_paths->length();
|
||||
if (num_paths != archived_num_module_paths) {
|
||||
return false;
|
||||
}
|
||||
return check_paths(header()->app_module_paths_start_index(), num_paths, module_paths, 0, 0);
|
||||
}
|
||||
|
||||
bool FileMapInfo::validate_shared_path_table() {
|
||||
@ -944,6 +964,16 @@ bool FileMapInfo::validate_shared_path_table() {
|
||||
|
||||
// Load the shared path table info from the archive header
|
||||
_shared_path_table = header()->shared_path_table();
|
||||
|
||||
bool matched_module_paths = true;
|
||||
if (CDSConfig::is_dumping_dynamic_archive() || header()->has_full_module_graph()) {
|
||||
matched_module_paths = check_module_paths();
|
||||
}
|
||||
if (header()->has_full_module_graph() && !matched_module_paths) {
|
||||
CDSConfig::stop_using_optimized_module_handling();
|
||||
log_info(cds)("optimized module handling: disabled because of mismatched module paths");
|
||||
}
|
||||
|
||||
if (CDSConfig::is_dumping_dynamic_archive()) {
|
||||
// Only support dynamic dumping with the usage of the default CDS archive
|
||||
// or a simple base archive.
|
||||
@ -959,7 +989,7 @@ bool FileMapInfo::validate_shared_path_table() {
|
||||
"Dynamic archiving is disabled because base layer archive has appended boot classpath");
|
||||
}
|
||||
if (header()->num_module_paths() > 0) {
|
||||
if (!check_module_paths()) {
|
||||
if (!matched_module_paths) {
|
||||
CDSConfig::disable_dumping_dynamic_archive();
|
||||
log_warning(cds)(
|
||||
"Dynamic archiving is disabled because base layer archive has a different module path");
|
||||
|
||||
@ -271,6 +271,7 @@ public:
|
||||
bool compressed_oops() const { return _compressed_oops; }
|
||||
bool compressed_class_pointers() const { return _compressed_class_ptrs; }
|
||||
HeapRootSegments heap_root_segments() const { return _heap_root_segments; }
|
||||
bool has_full_module_graph() const { return _has_full_module_graph; }
|
||||
size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos; }
|
||||
size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos; }
|
||||
size_t rw_ptrmap_start_pos() const { return _rw_ptrmap_start_pos; }
|
||||
@ -554,6 +555,7 @@ public:
|
||||
GrowableArray<const char*>* rp_array,
|
||||
unsigned int dumptime_prefix_len,
|
||||
unsigned int runtime_prefix_len) NOT_CDS_RETURN_(false);
|
||||
void extract_module_paths(const char* runtime_path, GrowableArray<const char*>* module_paths);
|
||||
bool validate_boot_class_paths() NOT_CDS_RETURN_(false);
|
||||
bool validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(false);
|
||||
bool map_heap_region_impl() NOT_CDS_JAVA_HEAP_RETURN_(false);
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "classfile/classLoaderExt.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/modules.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
@ -55,6 +56,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/typeArrayOop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
@ -875,6 +877,17 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
if (k->name()->equals("jdk/internal/module/ArchivedModuleGraph") &&
|
||||
!CDSConfig::is_using_optimized_module_handling() &&
|
||||
// archive was created with --module-path
|
||||
ClassLoaderExt::num_module_paths() > 0) {
|
||||
// ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path.
|
||||
// Thus, it might contain references to modules that do not exist at runtime. We cannot use it.
|
||||
log_info(cds, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d",
|
||||
BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()), ClassLoaderExt::num_module_paths());
|
||||
return;
|
||||
}
|
||||
|
||||
ExceptionMark em(THREAD);
|
||||
const ArchivedKlassSubGraphInfoRecord* record =
|
||||
resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/true, THREAD);
|
||||
@ -1123,6 +1136,13 @@ bool HeapShared::archive_reachable_objects_from(int level,
|
||||
// these objects that are referenced (directly or indirectly) by static fields.
|
||||
ResourceMark rm;
|
||||
log_error(cds, heap)("Cannot archive object of class %s", orig_obj->klass()->external_name());
|
||||
if (log_is_enabled(Trace, cds, heap)) {
|
||||
WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current();
|
||||
if (walker != nullptr) {
|
||||
LogStream ls(Log(cds, heap)::trace());
|
||||
CDSHeapVerifier::trace_to_root(&ls, walker->referencing_obj());
|
||||
}
|
||||
}
|
||||
MetaspaceShared::unrecoverable_writing_error();
|
||||
}
|
||||
|
||||
|
||||
@ -301,6 +301,7 @@ void MetaspaceShared::post_initialize(TRAPS) {
|
||||
}
|
||||
ClassLoaderExt::init_paths_start_index(info->app_class_paths_start_index());
|
||||
ClassLoaderExt::init_app_module_paths_start_index(info->app_module_paths_start_index());
|
||||
ClassLoaderExt::init_num_module_paths(info->header()->num_module_paths());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -792,6 +793,9 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
|
||||
// Do this at the very end, when no Java code will be executed. Otherwise
|
||||
// some new strings may be added to the intern table.
|
||||
StringTable::allocate_shared_strings_array(CHECK);
|
||||
} else {
|
||||
log_info(cds)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling");
|
||||
CDSConfig::stop_using_optimized_module_handling();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -582,6 +582,8 @@ void ClassLoader::setup_module_search_path(JavaThread* current, const char* path
|
||||
new_entry = create_class_path_entry(current, path, &st,
|
||||
false /*is_boot_append */, false /* from_class_path_attr */);
|
||||
if (new_entry != nullptr) {
|
||||
// ClassLoaderExt::process_module_table() filters out non-jar entries before calling this function.
|
||||
assert(new_entry->is_jar_file(), "module path entry %s is not a jar file", new_entry->name());
|
||||
add_to_module_path_entries(path, new_entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,6 +55,7 @@
|
||||
jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index;
|
||||
jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index;
|
||||
jshort ClassLoaderExt::_max_used_path_index = 0;
|
||||
int ClassLoaderExt::_num_module_paths = 0;
|
||||
bool ClassLoaderExt::_has_app_classes = false;
|
||||
bool ClassLoaderExt::_has_platform_classes = false;
|
||||
bool ClassLoaderExt::_has_non_jar_in_classpath = false;
|
||||
@ -89,21 +90,25 @@ void ClassLoaderExt::setup_app_search_path(JavaThread* current) {
|
||||
os::free(app_class_path);
|
||||
}
|
||||
|
||||
int ClassLoaderExt::compare_module_path_by_name(const char** p1, const char** p2) {
|
||||
return strcmp(*p1, *p2);
|
||||
}
|
||||
|
||||
void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* met) {
|
||||
ResourceMark rm(current);
|
||||
GrowableArray<char*>* module_paths = new GrowableArray<char*>(5);
|
||||
GrowableArray<const char*>* module_paths = new GrowableArray<const char*>(5);
|
||||
|
||||
class ModulePathsGatherer : public ModuleClosure {
|
||||
JavaThread* _current;
|
||||
GrowableArray<char*>* _module_paths;
|
||||
GrowableArray<const char*>* _module_paths;
|
||||
public:
|
||||
ModulePathsGatherer(JavaThread* current, GrowableArray<char*>* module_paths) :
|
||||
ModulePathsGatherer(JavaThread* current, GrowableArray<const char*>* module_paths) :
|
||||
_current(current), _module_paths(module_paths) {}
|
||||
void do_module(ModuleEntry* m) {
|
||||
char* uri = m->location()->as_C_string();
|
||||
if (strncmp(uri, "file:", 5) == 0) {
|
||||
char* path = ClassLoader::uri_to_path(uri);
|
||||
_module_paths->append(path);
|
||||
extract_jar_files_from_path(path, _module_paths);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -114,6 +119,10 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable*
|
||||
met->modules_do(&gatherer);
|
||||
}
|
||||
|
||||
// Sort the module paths before storing into CDS archive for simpler
|
||||
// checking at runtime.
|
||||
module_paths->sort(compare_module_path_by_name);
|
||||
|
||||
for (int i = 0; i < module_paths->length(); i++) {
|
||||
ClassLoader::setup_module_search_path(current, module_paths->at(i));
|
||||
}
|
||||
@ -129,6 +138,38 @@ void ClassLoaderExt::setup_module_paths(JavaThread* current) {
|
||||
process_module_table(current, met);
|
||||
}
|
||||
|
||||
bool ClassLoaderExt::has_jar_suffix(const char* filename) {
|
||||
// In jdk.internal.module.ModulePath.readModule(), it checks for the ".jar" suffix.
|
||||
// Performing the same check here.
|
||||
const char* dot = strrchr(filename, '.');
|
||||
if (dot != nullptr && strcmp(dot + 1, "jar") == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClassLoaderExt::extract_jar_files_from_path(const char* path, GrowableArray<const char*>* module_paths) {
|
||||
DIR* dirp = os::opendir(path);
|
||||
if (dirp == nullptr && errno == ENOTDIR && has_jar_suffix(path)) {
|
||||
module_paths->append(path);
|
||||
} else {
|
||||
if (dirp != nullptr) {
|
||||
struct dirent* dentry;
|
||||
while ((dentry = os::readdir(dirp)) != nullptr) {
|
||||
const char* file_name = dentry->d_name;
|
||||
if (has_jar_suffix(file_name)) {
|
||||
size_t full_name_len = strlen(path) + strlen(file_name) + strlen(os::file_separator()) + 1;
|
||||
char* full_name = NEW_RESOURCE_ARRAY(char, full_name_len);
|
||||
int n = os::snprintf(full_name, full_name_len, "%s%s%s", path, os::file_separator(), file_name);
|
||||
assert((size_t)n == full_name_len - 1, "Unexpected number of characters in string");
|
||||
module_paths->append(full_name);
|
||||
}
|
||||
}
|
||||
os::closedir(dirp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* ClassLoaderExt::read_manifest(JavaThread* current, ClassPathEntry* entry,
|
||||
jint *manifest_size, bool clean_text) {
|
||||
const char* name = "META-INF/MANIFEST.MF";
|
||||
|
||||
@ -53,12 +53,15 @@ private:
|
||||
static jshort _app_module_paths_start_index;
|
||||
// the largest path index being used during CDS dump time
|
||||
static jshort _max_used_path_index;
|
||||
// number of module paths
|
||||
static int _num_module_paths;
|
||||
|
||||
static bool _has_app_classes;
|
||||
static bool _has_platform_classes;
|
||||
static bool _has_non_jar_in_classpath;
|
||||
|
||||
static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size, bool clean_text);
|
||||
static bool has_jar_suffix(const char* filename);
|
||||
|
||||
public:
|
||||
static void process_jar_manifest(JavaThread* current, ClassPathEntry* entry);
|
||||
@ -68,6 +71,8 @@ public:
|
||||
|
||||
static void setup_search_paths(JavaThread* current);
|
||||
static void setup_module_paths(JavaThread* current);
|
||||
static void extract_jar_files_from_path(const char* path, GrowableArray<const char*>* module_paths);
|
||||
static int compare_module_path_by_name(const char** p1, const char** p2);
|
||||
|
||||
static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size) {
|
||||
// Remove all the new-line continuations (which wrap long lines at 72 characters, see
|
||||
@ -87,6 +92,8 @@ public:
|
||||
|
||||
static jshort max_used_path_index() { return _max_used_path_index; }
|
||||
|
||||
static int num_module_paths() { return _num_module_paths; }
|
||||
|
||||
static void set_max_used_path_index(jshort used_index) {
|
||||
_max_used_path_index = used_index;
|
||||
}
|
||||
@ -99,6 +106,10 @@ public:
|
||||
_app_module_paths_start_index = module_start;
|
||||
}
|
||||
|
||||
static void init_num_module_paths(int num_module_paths) {
|
||||
_num_module_paths = num_module_paths;
|
||||
}
|
||||
|
||||
static bool is_boot_classpath(int classpath_index) {
|
||||
return classpath_index < _app_class_paths_start_index;
|
||||
}
|
||||
|
||||
@ -336,6 +336,11 @@ bool Arguments::is_internal_module_property(const char* property) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if the key matches the --module-path property name ("jdk.module.path").
|
||||
bool Arguments::is_module_path_property(const char* key) {
|
||||
return (strcmp(key, MODULE_PROPERTY_PREFIX PATH) == 0);
|
||||
}
|
||||
|
||||
// Process java launcher properties.
|
||||
void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) {
|
||||
// See if sun.java.launcher or sun.java.launcher.is_altjvm is defined.
|
||||
|
||||
@ -461,6 +461,7 @@ class Arguments : AllStatic {
|
||||
static int PropertyList_readable_count(SystemProperty* pl);
|
||||
|
||||
static bool is_internal_module_property(const char* option);
|
||||
static bool is_module_path_property(const char* key);
|
||||
|
||||
// Miscellaneous System property value getter and setters.
|
||||
static void set_dll_dir(const char *value) { _sun_boot_library_path->set_value(value); }
|
||||
|
||||
@ -1084,5 +1084,8 @@ public class BuiltinClassLoader
|
||||
private void resetArchivedStates() {
|
||||
ucp = null;
|
||||
resourceCache = null;
|
||||
if (!moduleToReader.isEmpty()) {
|
||||
moduleToReader.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,13 +210,6 @@ public class ClassLoaders {
|
||||
protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
|
||||
return super.defineOrCheckPackage(pn, man, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the VM, during -Xshare:dump
|
||||
*/
|
||||
private void resetArchivedStates() {
|
||||
setClassPath(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -33,6 +33,7 @@ import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -139,7 +140,6 @@ public final class ModuleBootstrap {
|
||||
*/
|
||||
private static boolean canUseArchivedBootLayer() {
|
||||
return getProperty("jdk.module.upgrade.path") == null &&
|
||||
getProperty("jdk.module.path") == null &&
|
||||
getProperty("jdk.module.patch.0") == null && // --patch-module
|
||||
getProperty("jdk.module.addmods.0") == null && // --add-modules
|
||||
getProperty("jdk.module.limitmods") == null && // --limit-modules
|
||||
@ -203,7 +203,8 @@ public final class ModuleBootstrap {
|
||||
SystemModules systemModules = null;
|
||||
ModuleFinder systemModuleFinder;
|
||||
|
||||
boolean haveModulePath = (appModulePath != null || upgradeModulePath != null);
|
||||
boolean haveUpgradeModulePath = (upgradeModulePath != null);
|
||||
boolean haveModulePath = (appModulePath != null || haveUpgradeModulePath);
|
||||
boolean needResolution = true;
|
||||
boolean mayContainSplitPackages = true;
|
||||
boolean mayContainIncubatorModules = true;
|
||||
@ -463,7 +464,10 @@ public final class ModuleBootstrap {
|
||||
|
||||
// Step 8: CDS dump phase
|
||||
|
||||
if (CDS.isDumpingStaticArchive() && !haveModulePath && addModules.isEmpty()) {
|
||||
if (CDS.isDumpingStaticArchive()
|
||||
&& !haveUpgradeModulePath
|
||||
&& addModules.isEmpty()
|
||||
&& allJrtOrModularJar(cf)) {
|
||||
assert !isPatched;
|
||||
|
||||
// Archive module graph and maybe boot layer
|
||||
@ -510,6 +514,29 @@ public final class ModuleBootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all modules in the configuration are in the run-time image or
|
||||
* modular JAR files.
|
||||
*/
|
||||
private static boolean allJrtOrModularJar(Configuration cf) {
|
||||
return !cf.modules().stream()
|
||||
.map(m -> m.reference().location().orElseThrow())
|
||||
.anyMatch(uri -> !uri.getScheme().equalsIgnoreCase("jrt")
|
||||
&& !isJarFile(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given URI locates a jar file on the file system.
|
||||
*/
|
||||
private static boolean isJarFile(URI uri) {
|
||||
if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
Path path = Path.of(uri);
|
||||
return path.toString().endsWith(".jar") && Files.isRegularFile(path);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the configuration contains modules with overlapping packages.
|
||||
*/
|
||||
|
||||
@ -91,8 +91,19 @@ class ModuleReferences {
|
||||
ModulePatcher patcher,
|
||||
Path file) {
|
||||
URI uri = file.toUri();
|
||||
Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
|
||||
HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a);
|
||||
String fileString = file.toString();
|
||||
Supplier<ModuleReader> supplier = new Supplier<>() {
|
||||
@Override
|
||||
public ModuleReader get() {
|
||||
return new JarModuleReader(fileString, uri);
|
||||
}
|
||||
};
|
||||
HashSupplier hasher = new HashSupplier() {
|
||||
@Override
|
||||
public byte[] generate(String algorithm) {
|
||||
return ModuleHashes.computeHash(supplier, algorithm);
|
||||
}
|
||||
};
|
||||
return newModule(attrs, uri, supplier, patcher, hasher);
|
||||
}
|
||||
|
||||
@ -222,9 +233,9 @@ class ModuleReferences {
|
||||
private final JarFile jf;
|
||||
private final URI uri;
|
||||
|
||||
static JarFile newJarFile(Path path) {
|
||||
static JarFile newJarFile(String path) {
|
||||
try {
|
||||
return new JarFile(new File(path.toString()),
|
||||
return new JarFile(new File(path),
|
||||
true, // verify
|
||||
ZipFile.OPEN_READ,
|
||||
JarFile.runtimeVersion());
|
||||
@ -233,7 +244,7 @@ class ModuleReferences {
|
||||
}
|
||||
}
|
||||
|
||||
JarModuleReader(Path path, URI uri) {
|
||||
JarModuleReader(String path, URI uri) {
|
||||
this.jf = newJarFile(path);
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
@ -438,6 +438,8 @@ hotspot_appcds_dynamic = \
|
||||
-runtime/cds/appcds/complexURI \
|
||||
-runtime/cds/appcds/customLoader \
|
||||
-runtime/cds/appcds/dynamicArchive \
|
||||
-runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java \
|
||||
-runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java \
|
||||
-runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \
|
||||
-runtime/cds/appcds/javaldr/ArrayTest.java \
|
||||
-runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java \
|
||||
|
||||
@ -213,8 +213,10 @@ public class MainModuleOnly extends DynamicArchiveTestBase {
|
||||
"-cp", destJar.toString(),
|
||||
"--module-path", MODS_DIR.toString(),
|
||||
"-m", TEST_MODULE1 + "/" + MAIN_CLASS)
|
||||
.assertAbnormalExit(output -> {
|
||||
output.shouldMatch("Error: non-empty directory.*com.simple");
|
||||
// After JDK-8328313, non-empty module path directory won't be included
|
||||
// in the shared paths table.
|
||||
.assertNormalExit(output -> {
|
||||
output.shouldNotMatch("Error: non-empty directory.*com.simple");
|
||||
});
|
||||
|
||||
// test module path with very long length
|
||||
|
||||
@ -194,8 +194,10 @@ public class MainModuleOnly {
|
||||
output = TestCommon.createArchive(destJar.toString(), appClasses,
|
||||
"--module-path", MODS_DIR.toString(),
|
||||
"-m", mainModule);
|
||||
output.shouldHaveExitValue(1)
|
||||
.shouldMatch("Error: non-empty directory.*com.simple");
|
||||
// After JDK-8328313, non-empty module path directory won't be included
|
||||
// in the shared paths table.
|
||||
output.shouldHaveExitValue(0)
|
||||
.shouldNotMatch("Error: non-empty directory.*com.simple");
|
||||
|
||||
// test module path with very long length
|
||||
//
|
||||
|
||||
@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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 8328313
|
||||
* @requires vm.cds & !vm.graal.enabled & vm.cds.write.archived.java.heap
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
||||
* @run driver ModulePathAndFMG
|
||||
* @summary test module path changes for full module graph handling.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import jdk.test.lib.cds.CDSTestUtils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class ModulePathAndFMG {
|
||||
private static final String JAVA_HOME = System.getProperty("java.home");
|
||||
|
||||
private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir());
|
||||
|
||||
private static final String TEST_SRC = System.getProperty("test.src");
|
||||
|
||||
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
|
||||
private static final Path MODS_DIR = Paths.get("mody");
|
||||
private static final Path JMOD_DIR = Paths.get("jmod_dir");
|
||||
|
||||
// the module name of the test module
|
||||
private static final String MAIN_MODULE = "com.bars";
|
||||
private static final String TEST_MODULE = "com.foos";
|
||||
private static final String DUP_MODULE = "com.foos3";
|
||||
|
||||
// the module main class
|
||||
private static final String MAIN_CLASS = "com.bars.Main";
|
||||
private static final String TEST_CLASS = "com.foos.Test";
|
||||
|
||||
private static String PATH_LIBS = "modylibs";
|
||||
private static String DUP_LIBS = "duplibs";
|
||||
private static Path libsDir = null;
|
||||
private static Path dupDir = null;
|
||||
private static Path jmodDir = null;
|
||||
private static Path mainJar = null;
|
||||
private static Path testJar = null;
|
||||
private static Path dupJar = null;
|
||||
private static Path badJar = null;
|
||||
|
||||
private static String CLASS_FOUND_MESSAGE = "com.foos.Test found";
|
||||
private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test";
|
||||
private static String FIND_EXCEPTION_MESSAGE = "java.lang.module.FindException: Module com.foos not found, required by com.bars";
|
||||
private static String MODULE_NOT_RECOGNIZED = "Module format not recognized:.*modylibs.*com.bars.JAR";
|
||||
private static String OPTIMIZE_ENABLED = "] optimized module handling: enabled";
|
||||
private static String OPTIMIZE_DISABLED = "] optimized module handling: disabled";
|
||||
private static String FMG_ENABLED = "] full module graph: enabled";
|
||||
private static String FMG_DISABLED = "] full module graph: disabled";
|
||||
private static String MAIN_FROM_JAR = "class,load.*com.bars.Main.*[.]jar";
|
||||
private static String MAIN_FROM_CDS = "class,load.*com.bars.Main.*shared objects file";
|
||||
private static String MAIN_FROM_MODULE = "class,load.*com.bars.Main.*mody/com.bars";
|
||||
private static String TEST_FROM_JAR = "class,load.*com.foos.Test.*[.]jar";
|
||||
private static String TEST_FROM_CDS = "class,load.*com.foos.Test.*shared objects file";
|
||||
private static String MAP_FAILED = "Unable to use shared archive";
|
||||
private static String PATH_SEPARATOR = File.pathSeparator;
|
||||
private static String appClasses[] = {MAIN_CLASS, TEST_CLASS};
|
||||
private static String prefix[] = {"-Djava.class.path=", "-Xlog:cds,class+load,class+path=info"};
|
||||
|
||||
public static void buildTestModule() throws Exception {
|
||||
|
||||
// javac -d mods/$TESTMODULE src/$TESTMODULE/**
|
||||
JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE),
|
||||
MODS_DIR.resolve(TEST_MODULE),
|
||||
null);
|
||||
|
||||
// javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
|
||||
JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE),
|
||||
MODS_DIR.resolve(MAIN_MODULE),
|
||||
MODS_DIR.toString());
|
||||
|
||||
libsDir = Files.createTempDirectory(USER_DIR, PATH_LIBS);
|
||||
mainJar = libsDir.resolve(MAIN_MODULE + ".jar");
|
||||
testJar = libsDir.resolve(TEST_MODULE + ".jar");
|
||||
|
||||
// modylibs contains both modules com.foos.jar, com.bars.jar
|
||||
// build com.foos.jar
|
||||
String classes = MODS_DIR.resolve(TEST_MODULE).toString();
|
||||
JarBuilder.createModularJar(testJar.toString(), classes, TEST_CLASS);
|
||||
|
||||
// build com.bars.jar
|
||||
classes = MODS_DIR.resolve(MAIN_MODULE).toString();
|
||||
JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
|
||||
|
||||
dupDir = Files.createTempDirectory(USER_DIR, DUP_LIBS);
|
||||
dupJar = dupDir.resolve(DUP_MODULE + ".jar");
|
||||
Files.copy(testJar, dupJar, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
badJar = libsDir.resolve(MAIN_MODULE + ".JAR");
|
||||
Files.copy(mainJar, badJar, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
public static void buildJmod() throws Exception {
|
||||
Path jmod = Paths.get(JAVA_HOME, "bin", "jmod");
|
||||
jmodDir = Files.createDirectory(Paths.get(USER_DIR.toString() + File.separator + JMOD_DIR.toString()));
|
||||
OutputAnalyzer output = ProcessTools.executeProcess(jmod.toString(),
|
||||
"create",
|
||||
"--class-path", Paths.get(USER_DIR.toString(), MODS_DIR.toString(), TEST_MODULE).toString(),
|
||||
"--module-version", "1.0",
|
||||
"--main-class", TEST_CLASS,
|
||||
jmodDir.toString() + File.separator + TEST_MODULE + ".jmod");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
runWithModulePath();
|
||||
runWithExplodedModule();
|
||||
runWithJmodAndBadJar();
|
||||
}
|
||||
|
||||
private static void tty(String... args) {
|
||||
for (String s : args) {
|
||||
System.out.print(s + " ");
|
||||
}
|
||||
System.out.print("\n");
|
||||
}
|
||||
|
||||
public static void runWithModulePath() throws Exception {
|
||||
// compile the modules and create the modular jar files
|
||||
buildTestModule();
|
||||
// create an archive with the classes in the modules built in the
|
||||
// previous step
|
||||
OutputAnalyzer output = TestCommon.createArchive(
|
||||
null, appClasses,
|
||||
"--module-path",
|
||||
libsDir.toString(),
|
||||
"-m", MAIN_MODULE);
|
||||
TestCommon.checkDump(output);
|
||||
|
||||
tty("1. run with CDS on, with module path same as dump time");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
libsDir.toString(), // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_DISABLED)
|
||||
.shouldContain(OPTIMIZE_ENABLED)
|
||||
.shouldNotContain(FMG_DISABLED)
|
||||
.shouldContain(FMG_ENABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
|
||||
tty("2. run with CDS on, with jar on path");
|
||||
TestCommon.run("-Xlog:cds",
|
||||
"-Xlog:class+load",
|
||||
"-cp", mainJar.toString() + PATH_SEPARATOR + testJar.toString(),
|
||||
MAIN_CLASS)
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldContain(CLASS_FOUND_MESSAGE)
|
||||
.shouldMatch(MAIN_FROM_JAR)
|
||||
.shouldMatch(TEST_FROM_JAR)
|
||||
.shouldContain(OPTIMIZE_DISABLED)
|
||||
.shouldNotContain(OPTIMIZE_ENABLED)
|
||||
.shouldContain(FMG_DISABLED)
|
||||
.shouldNotContain(FMG_ENABLED);
|
||||
});
|
||||
|
||||
tty("3. run with CDS on, with --module-path, with jar should fail");
|
||||
TestCommon.run("-Xlog:cds",
|
||||
"-Xlog:class+load",
|
||||
"-p", libsDir.toString(),
|
||||
"-cp", mainJar.toString(),
|
||||
MAIN_CLASS)
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldContain(CLASS_NOT_FOUND_MESSAGE)
|
||||
.shouldMatch(MAIN_FROM_JAR)
|
||||
.shouldNotContain(FMG_ENABLED)
|
||||
.shouldNotContain(OPTIMIZE_ENABLED);
|
||||
});
|
||||
|
||||
final String modularJarPath = mainJar.toString() + PATH_SEPARATOR + testJar.toString();
|
||||
|
||||
tty("4. run with CDS on, with modular jars specified --module-path, should pass");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
modularJarPath, // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_DISABLED)
|
||||
.shouldContain(OPTIMIZE_ENABLED)
|
||||
.shouldNotContain(FMG_DISABLED)
|
||||
.shouldContain(FMG_ENABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS); // archived Main class is for module only
|
||||
});
|
||||
|
||||
final String extraModulePath = libsDir.toString() + PATH_SEPARATOR + dupDir.toString();
|
||||
// create an archive with an extra module which is not referenced
|
||||
output = TestCommon.createArchive(
|
||||
null, appClasses,
|
||||
"--module-path",
|
||||
extraModulePath,
|
||||
"-m", MAIN_MODULE);
|
||||
TestCommon.checkDump(output);
|
||||
|
||||
tty("5. run with CDS on, without the extra module specified in dump time, should pass");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
libsDir.toString(), // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_DISABLED)
|
||||
.shouldContain(OPTIMIZE_ENABLED)
|
||||
.shouldNotContain(FMG_DISABLED)
|
||||
.shouldContain(FMG_ENABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
tty("6. run with CDS on, with the extra module specified in dump time");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
extraModulePath, // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_ENABLED)
|
||||
.shouldContain(OPTIMIZE_DISABLED)
|
||||
.shouldNotContain(FMG_ENABLED)
|
||||
.shouldContain(FMG_DISABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
|
||||
final String extraJarPath = modularJarPath + PATH_SEPARATOR + dupJar.toString();
|
||||
|
||||
// create an archive by specifying modular jars in the --module-path with an extra module which is not referenced
|
||||
output = TestCommon.createArchive(
|
||||
null, appClasses,
|
||||
"--module-path",
|
||||
extraJarPath,
|
||||
"-m", MAIN_MODULE);
|
||||
TestCommon.checkDump(output);
|
||||
tty("7. run with CDS on, without the extra module specified in dump time, should pass");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
modularJarPath, // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_DISABLED)
|
||||
.shouldContain(OPTIMIZE_ENABLED)
|
||||
.shouldNotContain(FMG_DISABLED)
|
||||
.shouldContain(FMG_ENABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
|
||||
tty("8. run with CDS on, with the extra module specified in dump time");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
extraJarPath, // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_ENABLED)
|
||||
.shouldContain(OPTIMIZE_DISABLED)
|
||||
.shouldNotContain(FMG_ENABLED)
|
||||
.shouldContain(FMG_DISABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
tty("9. same as test case 8 but with paths instead of modular jars in the --module-path");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
extraModulePath, // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_ENABLED)
|
||||
.shouldContain(OPTIMIZE_DISABLED)
|
||||
.shouldNotContain(FMG_ENABLED)
|
||||
.shouldContain(FMG_DISABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
}
|
||||
|
||||
public static void runWithExplodedModule() throws Exception {
|
||||
// create an archive with an exploded module in the module path.
|
||||
OutputAnalyzer output = TestCommon.createArchive(
|
||||
null, appClasses,
|
||||
"--module-path",
|
||||
MODS_DIR.toString(),
|
||||
"-m", MAIN_MODULE + "/" + MAIN_CLASS);
|
||||
TestCommon.checkDump(output);
|
||||
|
||||
tty("10. run with CDS on, with exploded module in the module path");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
MODS_DIR.toString(), // --module-path
|
||||
MAIN_MODULE + "/" + MAIN_CLASS) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldContain(FMG_DISABLED)
|
||||
.shouldMatch(MAIN_FROM_MODULE) // Main class loaded from the exploded module
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
}
|
||||
|
||||
public static void runWithJmodAndBadJar() throws Exception {
|
||||
buildJmod();
|
||||
|
||||
final String modularJarPath = mainJar.toString() + PATH_SEPARATOR + testJar.toString();
|
||||
// create an archive with --module-path com.bars.jar:com.foos.jar
|
||||
OutputAnalyzer output = TestCommon.createArchive(
|
||||
null, appClasses,
|
||||
"--module-path",
|
||||
modularJarPath,
|
||||
"-m", MAIN_MODULE);
|
||||
TestCommon.checkDump(output);
|
||||
|
||||
String runModulePath = mainJar.toString() + PATH_SEPARATOR +
|
||||
jmodDir.toString() + TEST_MODULE + ".jmod";
|
||||
tty("11. run with CDS on, with module path com.bars.jar:com.foos.jmod");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
runModulePath, // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertAbnormalExit(out -> {
|
||||
out.shouldContain(OPTIMIZE_DISABLED)
|
||||
.shouldNotContain(OPTIMIZE_ENABLED)
|
||||
.shouldContain(FMG_DISABLED)
|
||||
.shouldNotContain(FMG_ENABLED)
|
||||
.shouldContain(FIND_EXCEPTION_MESSAGE);
|
||||
});
|
||||
|
||||
runModulePath += PATH_SEPARATOR + testJar.toString();
|
||||
tty("12. run with CDS on, with module path com.bars.jar:com.foos.jmod:com.foos.jar");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
runModulePath, // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_DISABLED)
|
||||
.shouldContain(OPTIMIZE_ENABLED)
|
||||
.shouldNotContain(FMG_DISABLED)
|
||||
.shouldContain(FMG_ENABLED)
|
||||
.shouldMatch(TEST_FROM_CDS)
|
||||
.shouldMatch(MAIN_FROM_CDS)
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
|
||||
runModulePath = badJar.toString() + PATH_SEPARATOR + testJar.toString();
|
||||
tty("13. run with CDS on, with module path com.bars.JAR:com.foos.jar");
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
runModulePath, // --module-path
|
||||
TEST_MODULE) // -m
|
||||
.assertAbnormalExit(out -> {
|
||||
out.shouldContain(OPTIMIZE_DISABLED)
|
||||
.shouldNotContain(OPTIMIZE_ENABLED)
|
||||
.shouldContain(FMG_DISABLED)
|
||||
.shouldNotContain(FMG_ENABLED)
|
||||
.shouldMatch(MODULE_NOT_RECOGNIZED);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @requires vm.cds & !vm.graal.enabled
|
||||
* @requires vm.cds & !vm.graal.enabled & vm.cds.write.archived.java.heap
|
||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
||||
* @run driver OptimizeModuleHandlingTest
|
||||
* @summary test module path changes for optimization of
|
||||
@ -64,8 +64,8 @@ public class OptimizeModuleHandlingTest {
|
||||
|
||||
private static String CLASS_FOUND_MESSAGE = "com.foos.Test found";
|
||||
private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test";
|
||||
private static String OPTIMIZE_ENABLED = "optimized module handling: enabled";
|
||||
private static String OPTIMIZE_DISABLED = "optimized module handling: disabled";
|
||||
private static String OPTIMIZE_ENABLED = "] optimized module handling: enabled";
|
||||
private static String OPTIMIZE_DISABLED = "] optimized module handling: disabled";
|
||||
private static String MAIN_FROM_JAR = "class,load.*com.bars.Main.*[.]jar";
|
||||
private static String MAIN_FROM_CDS = "class,load.*com.bars.Main.*shared objects file";
|
||||
private static String TEST_FROM_JAR = "class,load.*com.foos.Test.*[.]jar";
|
||||
@ -154,14 +154,14 @@ public class OptimizeModuleHandlingTest {
|
||||
|
||||
// Following 5 - 10 test with CDS on
|
||||
tty("5. run with CDS on, with module path");
|
||||
String prefix[] = {"-Djava.class.path=", "-Xlog:cds", "-Xlog:class+load"};
|
||||
String prefix[] = {"-Djava.class.path=", "-Xlog:cds,class+load,class+path=info"};
|
||||
TestCommon.runWithModules(prefix,
|
||||
null, // --upgrade-module-path
|
||||
libsDir.toString(), // --module-path
|
||||
MAIN_MODULE) // -m
|
||||
.assertNormalExit(out -> {
|
||||
out.shouldNotContain(OPTIMIZE_ENABLED)
|
||||
.shouldContain(OPTIMIZE_DISABLED)
|
||||
out.shouldNotContain(OPTIMIZE_DISABLED)
|
||||
.shouldContain(OPTIMIZE_ENABLED)
|
||||
.shouldMatch(MAIN_FROM_CDS) // // archived Main class is for module only
|
||||
.shouldContain(CLASS_FOUND_MESSAGE);
|
||||
});
|
||||
@ -174,8 +174,8 @@ public class OptimizeModuleHandlingTest {
|
||||
out.shouldContain(CLASS_FOUND_MESSAGE)
|
||||
.shouldMatch(MAIN_FROM_CDS)
|
||||
.shouldMatch(TEST_FROM_CDS)
|
||||
.shouldContain(OPTIMIZE_DISABLED)
|
||||
.shouldNotContain(OPTIMIZE_ENABLED);
|
||||
.shouldContain(OPTIMIZE_ENABLED)
|
||||
.shouldNotContain(OPTIMIZE_DISABLED);
|
||||
});
|
||||
tty("7. run with CDS on, with jar on path");
|
||||
TestCommon.run("-Xlog:cds",
|
||||
@ -231,7 +231,6 @@ public class OptimizeModuleHandlingTest {
|
||||
MAIN_CLASS)
|
||||
.assertAbnormalExit(out -> {
|
||||
out.shouldNotContain(CLASS_FOUND_MESSAGE)
|
||||
.shouldContain(OPTIMIZE_DISABLED) // mapping info
|
||||
.shouldContain("shared class paths mismatch");
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user