--- old/src/hotspot/share/classfile/classLoader.cpp 2018-04-02 14:11:34.505494506 -0700 +++ new/src/hotspot/share/classfile/classLoader.cpp 2018-04-02 14:11:34.242469722 -0700 @@ -148,6 +148,8 @@ #if INCLUDE_CDS ClassPathEntry* ClassLoader::_app_classpath_entries = NULL; ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL; +ClassPathEntry* ClassLoader::_module_path_entries = NULL; +ClassPathEntry* ClassLoader::_last_module_path_entry = NULL; SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL; #endif @@ -721,6 +723,11 @@ } } +void ClassLoader::setup_module_search_path(const char* path) { + check_shared_classpath(path); + update_module_path_entry_list(path); +} + #endif // Construct the array of module/path pairs as specified to --patch-module @@ -1088,6 +1095,41 @@ } } +#if INCLUDE_CDS +void ClassLoader::add_to_module_path_entries(const char* path, + ClassPathEntry* entry) { + assert(entry != NULL, "ClassPathEntry should not be NULL"); + ClassPathEntry* e = _module_path_entries; + + // The entry does not exist, add to the list + if (_module_path_entries == NULL) { + assert(_last_module_path_entry == NULL, "Sanity"); + _module_path_entries = _last_module_path_entry = entry; + } else { + _last_module_path_entry->set_next(entry); + _last_module_path_entry = entry; + } +} + +// Add a module path to the _module_path_entries list. +void ClassLoader::update_module_path_entry_list(const char *path, + bool throw_exception) { + struct stat st; + assert(os::stat(path, &st) == 0, "module path must exist"); + // File or directory found + ClassPathEntry* new_entry = NULL; + Thread* THREAD = Thread::current(); + new_entry = create_class_path_entry(path, &st, throw_exception, + false /*is_boot_append */, CHECK); + if (new_entry == NULL) { + return; + } + + add_to_module_path_entries(path, new_entry); + return; +} +#endif // INCLUDE_CDS + static void print_module_entry_table(const GrowableArray* const module_list) { ResourceMark rm; int num_of_entries = module_list->length(); @@ -1512,7 +1554,7 @@ } #if INCLUDE_CDS -static char* skip_uri_protocol(char* source) { +char* ClassLoader::skip_uri_protocol(char* source) { if (strncmp(source, "file:", 5) == 0) { // file: protocol path could start with file:/ or file:/// // locate the char after all the forward slashes @@ -1542,9 +1584,10 @@ return; } + oop loader = ik->class_loader(); char* src = (char*)stream->source(); if (src == NULL) { - if (ik->class_loader() == NULL) { + if (loader == NULL) { // JFR classes ik->set_shared_classpath_index(0); ik->set_class_loader_type(ClassLoader::BOOT_LOADER); @@ -1554,41 +1597,78 @@ assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build"); - ModuleEntry* module = ik->module(); - int classpath_index = -1; ResourceMark rm; - char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN); + Thread* THREAD = Thread::current(); + int classpath_index = -1; + PackageEntry* pkg_entry = ik->package(); - // save the path from the file: protocol or the module name from the jrt: protocol - // if no protocol prefix is found, path is the same as stream->source() - char* path = skip_uri_protocol(src); - for (int i = 0; i < FileMapInfo::get_number_of_share_classpaths(); i++) { - SharedClassPathEntry* ent = FileMapInfo::shared_classpath(i); - if (get_canonical_path(ent->name(), canonical_path, JVM_MAXPATHLEN)) { - // If the path (from the class stream srouce) is the same as the shared - // class path, then we have a match. For classes from module image loaded by the - // PlatformClassLoader, the stream->source() is not the name of the module image. - // Need to look for 'jrt:' explicitly. - if (strcmp(canonical_path, os::native_path((char*)path)) == 0 || - (i == 0 && string_starts_with(src, "jrt:"))) { - classpath_index = i; - break; + if (FileMapInfo::get_number_of_shared_paths() > 0) { + char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN); + + // save the path from the file: protocol or the module name from the jrt: protocol + // if no protocol prefix is found, path is the same as stream->source() + char* path = skip_uri_protocol(src); + for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) { + SharedClassPathEntry* ent = FileMapInfo::shared_path(i); + if (get_canonical_path(ent->name(), canonical_path, JVM_MAXPATHLEN)) { + // If the path (from the class stream source) is the same as the shared + // class or module path, then we have a match. + if (strcmp(canonical_path, os::native_path((char*)path)) == 0) { + // NULL pkg_entry and pkg_entry in an unnamed module implies the class + // is from the -cp. Ensure the index is within the -cp range before assigning + // to the classpath_index. + if ((pkg_entry == NULL) || (pkg_entry->in_unnamed_module())) { + if (SystemDictionary::is_system_class_loader(loader) && + (i >= ClassLoaderExt::app_class_paths_start_index()) && + (i < ClassLoaderExt::app_module_paths_start_index())) { + classpath_index = i; + break; + } else { + if ((i >= 1) && + (i < ClassLoaderExt::app_module_paths_start_index())) { + classpath_index = i; + break; + } + } + } else { + // non-NULL pkg_entry and is a named module implies the class is from the + // --module-path. Ensure the index is within the --module-path range before + // assigning to the classpath_index. + if ((pkg_entry != NULL) && !(pkg_entry->in_unnamed_module()) && (i > 0)) { + if (i >= ClassLoaderExt::app_module_paths_start_index() && + i < FileMapInfo::get_number_of_shared_paths()) { + classpath_index = i; + break; + } + } + } + } + // for index 0 and the stream->source() is the modules image or has the jrt: protocol. + // The class must be from the runtime modules image. + if (i == 0 && (is_modules_image(src) || string_starts_with(src, "jrt:"))) { + classpath_index = i; + break; + } } } - } - if (classpath_index < 0) { - // Shared classpath entry table only contains boot class path and -cp path. + // No path entry found for this class. Must be a shared class loaded by the // user defined classloader. - assert(ik->shared_classpath_index() < 0, "Sanity"); - return; + if (classpath_index < 0) { + assert(ik->shared_classpath_index() < 0, "Sanity"); + return; + } + } else { + assert(is_modules_image(src), "stream must be from modules image"); + assert(FileMapInfo::get_number_of_shared_paths() == 0, "shared path table must not have been setup"); + classpath_index = 0; } const char* const class_name = ik->name()->as_C_string(); const char* const file_name = file_name_for_class_name(class_name, ik->name()->utf8_length()); assert(file_name != NULL, "invariant"); - Thread* THREAD = Thread::current(); + ClassLoaderExt::Context context(class_name, file_name, CATCH); context.record_result(ik->name(), classpath_index, ik, THREAD); } @@ -1673,6 +1753,13 @@ _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check() } } + +void ClassLoader::initialize_module_path() { + if (DumpSharedSpaces) { + ClassLoaderExt::setup_module_paths(); + FileMapInfo::allocate_shared_path_table(); + } +} #endif jlong ClassLoader::classloader_time_ms() { --- old/src/hotspot/share/classfile/classLoader.hpp 2018-04-02 14:11:35.487587047 -0700 +++ new/src/hotspot/share/classfile/classLoader.hpp 2018-04-02 14:11:35.232563016 -0700 @@ -238,12 +238,18 @@ CDS_ONLY(static ClassPathEntry* _app_classpath_entries;) CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;) - CDS_ONLY(static void setup_app_search_path(const char *class_path);) + CDS_ONLY(static ClassPathEntry* _module_path_entries;) + CDS_ONLY(static ClassPathEntry* _last_module_path_entry;) + CDS_ONLY(static void setup_app_search_path(const char* class_path);) + CDS_ONLY(static void setup_module_search_path(const char* path);) static void add_to_app_classpath_entries(const char* path, ClassPathEntry* entry, bool check_for_duplicates); + CDS_ONLY(static void add_to_module_path_entries(const char* path, + ClassPathEntry* entry);) public: CDS_ONLY(static ClassPathEntry* app_classpath_entries() {return _app_classpath_entries;}) + CDS_ONLY(static ClassPathEntry* module_path_entries() {return _module_path_entries;}) protected: // Initialization: @@ -286,6 +292,8 @@ bool check_for_duplicates, bool is_boot_append, bool throw_exception=true); + CDS_ONLY(static void update_module_path_entry_list(const char *path, + bool throw_exception=true);) static void print_bootclasspath(); // Timing @@ -382,6 +390,7 @@ static void initialize(); static void classLoader_init2(TRAPS); CDS_ONLY(static void initialize_shared_path();) + CDS_ONLY(static void initialize_module_path();) static int compute_Object_vtable(); @@ -402,14 +411,28 @@ // entries during shared classpath setup time. static int num_app_classpath_entries(); + // Helper function used by CDS code to get the number of module path + // entries during shared classpath setup time. + static int num_module_path_entries() { + assert(DumpSharedSpaces, "Should only be called at CDS dump time"); + int num_entries = 0; + ClassPathEntry* e= ClassLoader::_module_path_entries; + while (e != NULL) { + num_entries ++; + e = e->next(); + } + return num_entries; + } static void check_shared_classpath(const char *path); static void finalize_shared_paths_misc_info(); static int get_shared_paths_misc_info_size(); static void* get_shared_paths_misc_info(); static bool check_shared_paths_misc_info(void* info, int size); + static int get_module_paths_misc_info_size(); + static void* get_module_paths_misc_info(); static void exit_with_path_failure(const char* error, const char* message); - - static void record_result(InstanceKlass* ik, const ClassFileStream* stream); + static char* skip_uri_protocol(char* source); + static void record_result(InstanceKlass* ik, const ClassFileStream* stream); #endif static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name, const char* file_name, jlong &size); --- old/src/hotspot/share/classfile/classLoaderExt.cpp 2018-04-02 14:11:36.460678739 -0700 +++ new/src/hotspot/share/classfile/classLoaderExt.cpp 2018-04-02 14:11:36.177652070 -0700 @@ -30,6 +30,7 @@ #include "classfile/classLoaderExt.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/klassFactory.hpp" +#include "classfile/modules.hpp" #include "classfile/sharedClassUtil.hpp" #include "classfile/sharedPathsMiscInfo.hpp" #include "classfile/systemDictionaryShared.hpp" @@ -41,19 +42,21 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/arguments.hpp" +#include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" #include "services/threadService.hpp" #include "utilities/stringUtils.hpp" -jshort ClassLoaderExt::_app_paths_start_index = ClassLoaderExt::max_classpath_index; +jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index; +jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index; bool ClassLoaderExt::_has_app_classes = false; bool ClassLoaderExt::_has_platform_classes = false; void ClassLoaderExt::setup_app_search_path() { assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS"); - _app_paths_start_index = ClassLoader::num_boot_classpath_entries(); + _app_class_paths_start_index = ClassLoader::num_boot_classpath_entries(); char* app_class_path = os::strdup(Arguments::get_appclasspath()); if (strcmp(app_class_path, ".") == 0) { @@ -68,6 +71,30 @@ } } +void ClassLoaderExt::process_module_table(ModuleEntryTable* met) { + ResourceMark rm; + for (int i = 0; i < met->table_size(); i++) { + for (ModuleEntry* m = met->bucket(i); m != NULL;) { + char* path = m->location()->as_C_string(); + if (strncmp(path, "file:", 5) == 0 && ClassLoader::string_ends_with(path, ".jar")) { + m->print(); + path = ClassLoader::skip_uri_protocol(path); + ClassLoader::setup_module_search_path(path); + } + m = m->next(); + } + } +} +void ClassLoaderExt::setup_module_search_path() { + assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS"); + _app_module_paths_start_index = ClassLoader::num_boot_classpath_entries() + + ClassLoader::num_app_classpath_entries(); + Thread* thread = Thread::current(); + Handle system_class_loader (thread, SystemDictionary::java_system_loader()); + ModuleEntryTable* met = Modules::get_module_entry_table(system_class_loader); + process_module_table(met); +} + char* ClassLoaderExt::read_manifest(ClassPathEntry* entry, jint *manifest_size, bool clean_text, TRAPS) { const char* name = "META-INF/MANIFEST.MF"; char* manifest; @@ -195,6 +222,12 @@ } } +void ClassLoaderExt::setup_module_paths() { + if (UseAppCDS) { + ClassLoaderExt::setup_module_search_path(); + } +} + Thread* ClassLoaderExt::Context::_dump_thread = NULL; void ClassLoaderExt::record_result(ClassLoaderExt::Context *context, --- old/src/hotspot/share/classfile/classLoaderExt.hpp 2018-04-02 14:11:37.439770998 -0700 +++ new/src/hotspot/share/classfile/classLoaderExt.hpp 2018-04-02 14:11:37.170745648 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP #include "classfile/classLoader.hpp" +#include "classfile/moduleEntry.hpp" #include "utilities/macros.hpp" CDS_ONLY(class SharedPathsMiscInfoExt;) @@ -59,14 +60,14 @@ _file_name = file_name; #if INCLUDE_CDS if (!DumpSharedSpaces && !UseSharedSpaces) { - // Must not modify _app_paths_start_index if we're not using CDS. - assert(_app_paths_start_index == ClassLoaderExt::max_classpath_index, "must be"); + // Must not modify _app_class_paths_start_index if we're not using CDS. + assert(_app_class_paths_start_index == ClassLoaderExt::max_classpath_index, "must be"); } #endif } bool should_verify(int classpath_index) { - CDS_ONLY(return (classpath_index >= _app_paths_start_index);) + CDS_ONLY(return (classpath_index >= _app_class_paths_start_index);) NOT_CDS(return false;) } @@ -82,8 +83,8 @@ ~Context() { #if INCLUDE_CDS if (!DumpSharedSpaces && !UseSharedSpaces) { - // Must not modify app_paths_start_index if we're not using CDS. - assert(_app_paths_start_index == ClassLoaderExt::max_classpath_index, "must be"); + // Must not modify app_class_paths_start_index if we're not using CDS. + assert(_app_class_paths_start_index == ClassLoaderExt::max_classpath_index, "must be"); } #endif } @@ -93,10 +94,16 @@ #if INCLUDE_CDS static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size); static void setup_app_search_path(); // Only when -Xshare:dump + static void process_module_table(ModuleEntryTable* met); + static void setup_module_search_path(); static SharedPathsMiscInfoExt* shared_paths_misc_info() { return (SharedPathsMiscInfoExt*)_shared_paths_misc_info; } - static jshort _app_paths_start_index; // index of first app JAR in shared classpath entry table + // index of first app JAR in shared classpath entry table + static jshort _app_class_paths_start_index; + // index of first modular JAR in shared modulepath entry table + static jshort _app_module_paths_start_index; + static bool _has_app_classes; static bool _has_platform_classes; #endif @@ -116,6 +123,7 @@ } static void setup_search_paths() NOT_CDS_RETURN; + static void setup_module_paths() NOT_CDS_RETURN; #if INCLUDE_CDS private: @@ -137,14 +145,20 @@ static void finalize_shared_paths_misc_info(); - static jshort app_paths_start_index() { return _app_paths_start_index; } + static jshort app_class_paths_start_index() { return _app_class_paths_start_index; } + + static jshort app_module_paths_start_index() { return _app_module_paths_start_index; } static void init_paths_start_index(jshort app_start) { - _app_paths_start_index = app_start; + _app_class_paths_start_index = app_start; + } + + static void init_app_module_paths_start_index(jshort module_start) { + _app_module_paths_start_index = module_start; } static bool is_boot_classpath(int classpath_index) { - return classpath_index < _app_paths_start_index; + return classpath_index < _app_class_paths_start_index; } static bool has_platform_or_app_classes() { --- old/src/hotspot/share/classfile/klassFactory.cpp 2018-04-02 14:11:38.422863633 -0700 +++ new/src/hotspot/share/classfile/klassFactory.cpp 2018-04-02 14:11:38.168839696 -0700 @@ -84,7 +84,7 @@ } } else { SharedClassPathEntry* ent = - (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); + (SharedClassPathEntry*)FileMapInfo::shared_path(path_index); pathname = ent == NULL ? NULL : ent->name(); } ClassFileStream* stream = new ClassFileStream(ptr, --- old/src/hotspot/share/classfile/modules.cpp 2018-04-02 14:11:39.390954854 -0700 +++ new/src/hotspot/share/classfile/modules.cpp 2018-04-02 14:11:39.135930824 -0700 @@ -85,7 +85,7 @@ return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version)); } -static ModuleEntryTable* get_module_entry_table(Handle h_loader) { +ModuleEntryTable* Modules::get_module_entry_table(Handle h_loader) { // This code can be called during start-up, before the classLoader's classLoader data got // created. So, call register_loader() to make sure the classLoader data gets created. ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader); --- old/src/hotspot/share/classfile/modules.hpp 2018-04-02 14:11:40.243035144 -0700 +++ new/src/hotspot/share/classfile/modules.hpp 2018-04-02 14:11:39.973009700 -0700 @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "runtime/handles.hpp" +class ModuleEntryTable; class Symbol; class Modules : AllStatic { @@ -122,6 +123,7 @@ // Return TRUE iff package is defined by loader static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS); + static ModuleEntryTable* get_module_entry_table(Handle h_loader); }; #endif // SHARE_VM_CLASSFILE_MODULES_HPP --- old/src/hotspot/share/classfile/sharedClassUtil.cpp 2018-04-02 14:11:41.078113832 -0700 +++ new/src/hotspot/share/classfile/sharedClassUtil.cpp 2018-04-02 14:11:40.819089425 -0700 @@ -93,6 +93,9 @@ case APP: ClassLoader::trace_class_path("Expecting -Djava.class.path=", path); break; + case MODULE: + ClassLoader::trace_class_path("Checking module path: ", path); + break; default: SharedPathsMiscInfo::print_path(out, type, path); } @@ -167,12 +170,13 @@ void SharedClassUtil::initialize(TRAPS) { if (UseSharedSpaces) { - int size = FileMapInfo::get_number_of_share_classpaths(); + int size = FileMapInfo::get_number_of_shared_paths(); if (size > 0) { SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD); if (!DumpSharedSpaces) { FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); - ClassLoaderExt::init_paths_start_index(header->_app_paths_start_index); + ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index); + ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index); } } } @@ -208,7 +212,7 @@ bool SharedClassUtil::is_classpath_entry_signed(int classpath_index) { assert(classpath_index >= 0, "Sanity"); SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*) - FileMapInfo::shared_classpath(classpath_index); + FileMapInfo::shared_path(classpath_index); return ent->_is_signed; } @@ -216,7 +220,8 @@ FileMapInfo::FileMapHeader::populate(mapinfo, alignment); ClassLoaderExt::finalize_shared_paths_misc_info(); - _app_paths_start_index = ClassLoaderExt::app_paths_start_index(); + _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index(); + _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index(); _verify_local = BytecodeVerificationLocal; _verify_remote = BytecodeVerificationRemote; --- old/src/hotspot/share/classfile/sharedClassUtil.hpp 2018-04-02 14:11:41.942195253 -0700 +++ new/src/hotspot/share/classfile/sharedClassUtil.hpp 2018-04-02 14:11:41.653168018 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,10 +34,11 @@ class FileMapHeaderExt: public FileMapInfo::FileMapHeader { public: - jshort _app_paths_start_index; // Index of first app classpath entry - bool _verify_local; // BytecodeVerificationLocal setting - bool _verify_remote; // BytecodeVerificationRemote setting - bool _has_platform_or_app_classes; // Archive contains app classes + jshort _app_class_paths_start_index; // Index of first app classpath entry + jshort _app_module_paths_start_index; // Index of first module path entry + bool _verify_local; // BytecodeVerificationLocal setting + bool _verify_remote; // BytecodeVerificationRemote setting + bool _has_platform_or_app_classes; // Archive contains app classes FileMapHeaderExt() { _has_platform_or_app_classes = true; @@ -56,12 +57,14 @@ int _app_offset; public: enum { - APP = 5 + APP = 5, + MODULE = 6 }; virtual const char* type_name(int type) { switch (type) { case APP: return "APP"; + case MODULE: return "MODULE"; default: return SharedPathsMiscInfo::type_name(type); } } --- old/src/hotspot/share/classfile/systemDictionary.cpp 2018-04-02 14:11:42.789275072 -0700 +++ new/src/hotspot/share/classfile/systemDictionary.cpp 2018-04-02 14:11:42.519249628 -0700 @@ -1210,7 +1210,7 @@ } } SharedClassPathEntry* ent = - (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); + (SharedClassPathEntry*)FileMapInfo::shared_path(path_index); if (!Universe::is_module_initialized()) { assert(ent != NULL && ent->is_modules_image(), "Loading non-bootstrap classes before the module system is initialized"); --- old/src/hotspot/share/classfile/systemDictionaryShared.cpp 2018-04-02 14:11:43.807371005 -0700 +++ new/src/hotspot/share/classfile/systemDictionaryShared.cpp 2018-04-02 14:11:43.539345750 -0700 @@ -92,7 +92,7 @@ Handle empty; Handle manifest ; if (shared_jar_manifest(shared_path_index) == NULL) { - SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)FileMapInfo::shared_classpath(shared_path_index); + SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)FileMapInfo::shared_path(shared_path_index); long size = ent->manifest_size(); if (size <= 0) { return empty; // No manifest - return NULL handle @@ -138,7 +138,7 @@ Handle url_h; if (shared_jar_url(shared_path_index) == NULL) { JavaValue result(T_OBJECT); - const char* path = FileMapInfo::shared_classpath_name(shared_path_index); + const char* path = FileMapInfo::shared_path_name(shared_path_index); Handle path_string = java_lang_String::create_from_str(path, CHECK_(url_h)); Klass* classLoaders_klass = SystemDictionary::jdk_internal_loader_ClassLoaders_klass(); @@ -304,7 +304,7 @@ int index = ik->shared_classpath_index(); assert(index >= 0, "Sanity"); SharedClassPathEntryExt* ent = - (SharedClassPathEntryExt*)FileMapInfo::shared_classpath(index); + (SharedClassPathEntryExt*)FileMapInfo::shared_path(index); Symbol* class_name = ik->name(); if (ent->is_modules_image()) { @@ -328,13 +328,13 @@ // For shared app/platform classes originated from JAR files on the class path: // Each of the 3 SystemDictionaryShared::_shared_xxx arrays has the same length // as the shared classpath table in the shared archive (see - // FileMap::_classpath_entry_table in filemap.hpp for details). + // FileMap::_shared_path_table in filemap.hpp for details). // // If a shared InstanceKlass k is loaded from the class path, let // // index = k->shared_classpath_index(): // - // FileMap::_classpath_entry_table[index] identifies the JAR file that contains k. + // FileMap::_shared_path_table[index] identifies the JAR file that contains k. // // k's protection domain is: // @@ -358,9 +358,7 @@ } // Currently AppCDS only archives classes from the run-time image, the -// -Xbootclasspath/a path, and the class path. The following rules need to be -// revised when AppCDS is changed to archive classes from other code sources -// in the future, for example the module path (specified by -p). +// -Xbootclasspath/a path, the class path, and the module path. // // Check if a shared class can be loaded by the specific classloader. Following // are the "visible" archived classes for different classloaders. @@ -368,10 +366,10 @@ // NULL classloader: // - see SystemDictionary::is_shared_class_visible() // Platform classloader: -// - Module class from "modules" jimage. ModuleEntry must be defined in the +// - Module class from runtime image. ModuleEntry must be defined in the // classloader. -// App Classloader: -// - Module class from "modules" jimage. ModuleEntry must be defined in the +// App classloader: +// - Module Class from runtime image and module path. ModuleEntry must be defined in the // classloader. // - Class from -cp. The class must have no PackageEntry defined in any of the // boot/platform/app classloader, or must be in the unnamed module defined in the @@ -386,10 +384,11 @@ TRAPS) { assert(class_loader.not_null(), "Class loader should not be NULL"); assert(Universe::is_module_initialized(), "Module system is not initialized"); + ResourceMark rm(THREAD); int path_index = ik->shared_classpath_index(); SharedClassPathEntry* ent = - (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); + (SharedClassPathEntry*)FileMapInfo::shared_path(path_index); if (SystemDictionary::is_platform_class_loader(class_loader())) { assert(ent != NULL, "shared class for PlatformClassLoader should have valid SharedClassPathEntry"); @@ -400,7 +399,7 @@ // PackageEntry/ModuleEntry is found in the classloader. Check if the // ModuleEntry's location agrees with the archived class' origination. if (ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) { - return true; // Module class from the "modules" jimage + return true; // Module class from the runtime image } } } else if (SystemDictionary::is_system_class_loader(class_loader())) { @@ -409,7 +408,8 @@ // The archived class is in the unnamed package. Currently, the boot image // does not contain any class in the unnamed package. assert(!ent->is_modules_image(), "Class in the unnamed package must be from the classpath"); - if (path_index >= ClassLoaderExt::app_paths_start_index()) { + if (path_index >= ClassLoaderExt::app_class_paths_start_index()) { + assert(path_index < ClassLoaderExt::app_module_paths_start_index(), "invalid path_index"); return true; } } else { @@ -421,23 +421,37 @@ if (get_package_entry(pkg_name, ClassLoaderData::class_loader_data_or_null(SystemDictionary::java_platform_loader())) == NULL && get_package_entry(pkg_name, ClassLoaderData::the_null_class_loader_data()) == NULL) { // The PackageEntry is not defined in any of the boot/platform/app classloaders. - // The archived class must from -cp path and not from the run-time image. - if (!ent->is_modules_image() && path_index >= ClassLoaderExt::app_paths_start_index()) { + // The archived class must from -cp path and not from the runtime image. + if (!ent->is_modules_image() && path_index >= ClassLoaderExt::app_class_paths_start_index() && + path_index < ClassLoaderExt::app_module_paths_start_index()) { return true; } } } else if (mod_entry != NULL) { - // The package/module is defined in the AppClassLoader. Currently we only - // support archiving application module class from the run-time image. + // The package/module is defined in the AppClassLoader. We support + // archiving application module class from the runtime image or from + // a named module from a module path. // Packages from the -cp path are in the unnamed_module. - if ((ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) || - (pkg_entry->in_unnamed_module() && path_index >= ClassLoaderExt::app_paths_start_index())) { + if (ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) { + // shared module class from runtime image + return true; + } else if (pkg_entry->in_unnamed_module() && path_index >= ClassLoaderExt::app_class_paths_start_index() && + path_index < ClassLoaderExt::app_module_paths_start_index()) { + // shared class from -cp DEBUG_ONLY( \ ClassLoaderData* loader_data = class_loader_data(class_loader); \ - if (pkg_entry->in_unnamed_module()) \ - assert(mod_entry == loader_data->unnamed_module(), "the unnamed module is not defined in the classloader");) - + assert(mod_entry == loader_data->unnamed_module(), "the unnamed module is not defined in the classloader");) return true; + } else { + if(!pkg_entry->in_unnamed_module() && + (path_index >= ClassLoaderExt::app_module_paths_start_index())&& + (path_index < FileMapInfo::get_number_of_shared_paths()) && + (strcmp(ent->name(), ClassLoader::skip_uri_protocol(mod_entry->location()->as_C_string())) == 0)) { + // shared module class from module path + return true; + } else { + assert(path_index < FileMapInfo::get_number_of_shared_paths(), "invalid path_index"); + } } } } --- old/src/hotspot/share/memory/filemap.cpp 2018-04-02 14:11:44.837468069 -0700 +++ new/src/hotspot/share/memory/filemap.cpp 2018-04-02 14:11:44.556441589 -0700 @@ -96,7 +96,7 @@ va_list ap; va_start(ap, msg); MetaspaceShared::set_archive_loading_failed(); - if (PrintSharedArchiveAndExit && _validating_classpath_entry_table) { + if (PrintSharedArchiveAndExit && _validating_shared_path_table) { // If we are doing PrintSharedArchiveAndExit and some of the classpath entries // do not validate, we can still continue "limping" to validate the remaining // entries. No need to quit. @@ -188,9 +188,9 @@ _max_heap_size = MaxHeapSize; _narrow_klass_base = Universe::narrow_klass_base(); _narrow_klass_shift = Universe::narrow_klass_shift(); - _classpath_entry_table_size = mapinfo->_classpath_entry_table_size; - _classpath_entry_table = mapinfo->_classpath_entry_table; - _classpath_entry_size = mapinfo->_classpath_entry_size; + _shared_path_table_size = mapinfo->_shared_path_table_size; + _shared_path_table = mapinfo->_shared_path_table; + _shared_path_entry_size = mapinfo->_shared_path_entry_size; // The following fields are for sanity checks for whether this archive // will function correctly with this JVM and the bootclasspath it's @@ -231,15 +231,15 @@ strcpy(_name->data(), name); } -bool SharedClassPathEntry::validate() { +bool SharedClassPathEntry::validate(bool is_class_path) { struct stat st; const char* name = this->name(); bool ok = true; log_info(class, path)("checking shared classpath entry: %s", name); - if (os::stat(name, &st) != 0) { + if (os::stat(name, &st) != 0 && is_class_path) { FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name); ok = false; - } else if (is_dir()) { + } else if (is_dir() && is_class_path) { if (!os::dir_is_empty(name)) { FileMapInfo::fail_continue("directory is not empty: %s", name); ok = false; @@ -266,7 +266,7 @@ it->push(&_manifest); } -void FileMapInfo::allocate_classpath_entry_table() { +void FileMapInfo::allocate_shared_path_table() { assert(DumpSharedSpaces, "Sanity"); Thread* THREAD = Thread::current(); @@ -279,12 +279,13 @@ size_t entry_size = SharedClassUtil::shared_class_path_entry_size(); // assert ( should be 8 byte aligned??) int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries(); int num_app_classpath_entries = ClassLoader::num_app_classpath_entries(); - int num_entries = num_boot_classpath_entries + num_app_classpath_entries; + int num_module_path_entries = ClassLoader::num_module_path_entries(); + int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries; size_t bytes = entry_size * num_entries; - _classpath_entry_table = MetadataFactory::new_array(loader_data, (int)(bytes + 7 / 8), THREAD); - _classpath_entry_table_size = num_entries; - _classpath_entry_size = entry_size; + _shared_path_table = MetadataFactory::new_array(loader_data, (int)(bytes + 7 / 8), THREAD); + _shared_path_table_size = num_entries; + _shared_path_entry_size = entry_size; // 1. boot class path int i = 0; @@ -292,7 +293,7 @@ while (cpe != NULL) { const char* type = ((cpe == jrt) ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir")); log_info(class, path)("add main shared path (%s) %s", type, cpe->name()); - SharedClassPathEntry* ent = shared_classpath(i); + SharedClassPathEntry* ent = shared_path(i); ent->init(cpe->name(), THREAD); if (cpe != jrt) { // No need to do jimage. EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. @@ -308,41 +309,65 @@ ClassPathEntry *acpe = ClassLoader::app_classpath_entries(); while (acpe != NULL) { log_info(class, path)("add app shared path %s", acpe->name()); - SharedClassPathEntry* ent = shared_classpath(i); + SharedClassPathEntry* ent = shared_path(i); ent->init(acpe->name(), THREAD); EXCEPTION_MARK; SharedClassUtil::update_shared_classpath(acpe, ent, THREAD); acpe = acpe->next(); - i ++; + i++; + } + + // 3. module path + ClassPathEntry *mpe = ClassLoader::module_path_entries(); + while (mpe != NULL) { + log_info(class, path)("add module path %s",mpe->name()); + SharedClassPathEntry* ent = shared_path(i); + ent->init(mpe->name(), THREAD); + EXCEPTION_MARK; + SharedClassUtil::update_shared_classpath(mpe, ent, THREAD); + mpe = mpe->next(); + i++; } - assert(i == num_entries, "number of app class path entry mismatch"); + assert(i == num_entries, "number of shared path entry mismatch"); } -bool FileMapInfo::validate_classpath_entry_table() { - _validating_classpath_entry_table = true; +bool FileMapInfo::validate_shared_path_table() { + _validating_shared_path_table = true; - int count = _header->_classpath_entry_table_size; + _shared_path_table = _header->_shared_path_table; + _shared_path_entry_size = _header->_shared_path_entry_size; + _shared_path_table_size = _header->_shared_path_table_size; - _classpath_entry_table = _header->_classpath_entry_table; - _classpath_entry_size = _header->_classpath_entry_size; - _classpath_entry_table_size = _header->_classpath_entry_table_size; + // Note: _app_module_paths_start_index may not have a valid value if the UseAppCDS flag + // wasn't enabled during dump time. Therefore, we need to use the smaller of + // _shared_path_table_size and _app_module_paths_start_index for the _app_module_paths_start_index. + FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header(); + int module_paths_start_index = (header->_app_module_paths_start_index >= _shared_path_table_size) ? + _shared_path_table_size : header->_app_module_paths_start_index; + + int count = _shared_path_table_size; for (int i=0; ivalidate()) { - log_info(class, path)("ok"); + if (i < module_paths_start_index) { + if (shared_path(i)->validate()) { + log_info(class, path)("ok"); + } + } else if (i >= module_paths_start_index) { + if (shared_path(i)->validate(false /* not a class path entry */)) { + log_info(class, path)("ok"); + } } else if (!PrintSharedArchiveAndExit) { - _validating_classpath_entry_table = false; - _classpath_entry_table = NULL; - _classpath_entry_table_size = 0; + _validating_shared_path_table = false; + _shared_path_table = NULL; + _shared_path_table_size = 0; return false; } } - _validating_classpath_entry_table = false; + _validating_shared_path_table = false; return true; } - // Read the FileMapInfo information from the file. bool FileMapInfo::init_from_file(int fd) { @@ -925,18 +950,18 @@ } void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it) { - it->push(&_classpath_entry_table); - for (int i=0; i<_classpath_entry_table_size; i++) { - shared_classpath(i)->metaspace_pointers_do(it); + it->push(&_shared_path_table); + for (int i=0; i<_shared_path_table_size; i++) { + shared_path(i)->metaspace_pointers_do(it); } } FileMapInfo* FileMapInfo::_current_info = NULL; -Array* FileMapInfo::_classpath_entry_table = NULL; -int FileMapInfo::_classpath_entry_table_size = 0; -size_t FileMapInfo::_classpath_entry_size = 0x1234baad; -bool FileMapInfo::_validating_classpath_entry_table = false; +Array* FileMapInfo::_shared_path_table = NULL; +int FileMapInfo::_shared_path_table_size = 0; +size_t FileMapInfo::_shared_path_entry_size = 0x1234baad; +bool FileMapInfo::_validating_shared_path_table = false; // Open the shared archive file, read and validate the header // information (version, boot classpath, etc.). If initialization @@ -946,7 +971,7 @@ // Validation of the archive is done in two steps: // // [1] validate_header() - done here. This checks the header, including _paths_misc_info. -// [2] validate_classpath_entry_table - this is done later, because the table is in the RW +// [2] validate_shared_path_table - this is done later, because the table is in the RW // region of the archive, which is not mapped yet. bool FileMapInfo::initialize() { assert(UseSharedSpaces, "UseSharedSpaces expected."); --- old/src/hotspot/share/memory/filemap.hpp 2018-04-02 14:11:45.815560233 -0700 +++ new/src/hotspot/share/memory/filemap.hpp 2018-04-02 14:11:45.558536014 -0700 @@ -53,7 +53,7 @@ public: void init(const char* name, TRAPS); void metaspace_pointers_do(MetaspaceClosure* it); - bool validate(); + bool validate(bool is_class_path = true); // The _timestamp only gets set for jar files and "modules" jimage. bool is_jar_or_bootimage() { @@ -85,10 +85,10 @@ size_t _file_offset; private: - static Array* _classpath_entry_table; - static int _classpath_entry_table_size; - static size_t _classpath_entry_size; - static bool _validating_classpath_entry_table; + static Array* _shared_path_table; + static int _shared_path_table_size; + static size_t _shared_path_entry_size; + static bool _validating_shared_path_table; // FileMapHeader describes the shared space data in the file to be // mapped. This structure gets written to a file. It is not a class, so @@ -153,7 +153,7 @@ // checking the validity of the archive and is deallocated after the archive is loaded. // // Note that the _paths_misc_info does NOT include information for JAR files - // that existed during dump time. Their information is stored in _classpath_entry_table. + // that existed during dump time. Their information is stored in _shared_path_table. int _paths_misc_info_size; // The following is a table of all the class path entries that were used @@ -167,9 +167,9 @@ // FIXME -- if JAR files in the tail of the list were specified but not used during dumping, // they should be removed from this table, to save space and to avoid spurious // loading failures during runtime. - int _classpath_entry_table_size; - size_t _classpath_entry_size; - Array* _classpath_entry_table; + int _shared_path_table_size; + size_t _shared_path_entry_size; + Array* _shared_path_table; char* region_addr(int idx); @@ -270,25 +270,26 @@ // Stop CDS sharing and unmap CDS regions. static void stop_sharing_and_unmap(const char* msg); - static void allocate_classpath_entry_table(); - bool validate_classpath_entry_table(); + static void allocate_shared_path_table(); + bool validate_shared_path_table(); - static SharedClassPathEntry* shared_classpath(int index) { + static SharedClassPathEntry* shared_path(int index) { if (index < 0) { return NULL; } - assert(index < _classpath_entry_table_size, "sanity"); - char* p = (char*)_classpath_entry_table->data(); - p += _classpath_entry_size * index; + assert(index < _shared_path_table_size, "sanity"); + char* p = (char*)_shared_path_table->data(); + p += _shared_path_entry_size * index; return (SharedClassPathEntry*)p; } - static const char* shared_classpath_name(int index) { + + static const char* shared_path_name(int index) { assert(index >= 0, "Sanity"); - return shared_classpath(index)->name(); + return shared_path(index)->name(); } - static int get_number_of_share_classpaths() { - return _classpath_entry_table_size; + static int get_number_of_shared_paths() { + return _shared_path_table_size; } private: --- old/src/hotspot/share/memory/metaspaceShared.cpp 2018-04-02 14:11:46.831655978 -0700 +++ new/src/hotspot/share/memory/metaspaceShared.cpp 2018-04-02 14:11:46.557630157 -0700 @@ -1619,7 +1619,6 @@ void MetaspaceShared::prepare_for_dumping() { Arguments::check_unsupported_dumping_properties(); ClassLoader::initialize_shared_path(); - FileMapInfo::allocate_classpath_entry_table(); } // Preload classes from a list, populate the shared spaces and dump to a @@ -2001,7 +2000,7 @@ (md_base = mapinfo->map_region(md, &md_top)) != NULL && (od_base = mapinfo->map_region(od, &od_top)) != NULL && (image_alignment == (size_t)os::vm_allocation_granularity()) && - mapinfo->validate_classpath_entry_table()) { + mapinfo->validate_shared_path_table()) { // Success -- set up MetaspaceObj::_shared_metaspace_{base,top} for // fast checking in MetaspaceShared::is_in_shared_metaspace() and // MetaspaceObj::is_shared(). --- old/src/hotspot/share/oops/klass.hpp 2018-04-02 14:11:47.868753702 -0700 +++ new/src/hotspot/share/oops/klass.hpp 2018-04-02 14:11:47.572725808 -0700 @@ -150,7 +150,7 @@ int _vtable_len; private: - // This is an index into FileMapHeader::_classpath_entry_table[], to + // This is an index into FileMapHeader::_shared_path_table[], to // associate this class with the JAR file where it's loaded from during // dump time. If a class is not loaded from the shared archive, this field is // -1. --- old/src/hotspot/share/runtime/arguments.cpp 2018-04-02 14:11:48.869848033 -0700 +++ new/src/hotspot/share/runtime/arguments.cpp 2018-04-02 14:11:48.597822401 -0700 @@ -1446,35 +1446,23 @@ } #if INCLUDE_CDS +const char* unsupported_properties[] = { "jdk.module.limitmods", + "jdk.module.upgrade.path", + "jdk.module.patch.0" }; +const char* unsupported_options[] = { "--limit-modules", + "--upgrade-module-path", + "--patch-module" + }; void Arguments::check_unsupported_dumping_properties() { assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); - const char* unsupported_properties[] = { "jdk.module.main", - "jdk.module.limitmods", - "jdk.module.path", - "jdk.module.upgrade.path", - "jdk.module.patch.0" }; - const char* unsupported_options[] = { "-m", // cannot use at dump time - "--limit-modules", // ignored at dump time - "--module-path", // ignored at dump time - "--upgrade-module-path", // ignored at dump time - "--patch-module" // ignored at dump time - }; assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be"); - // If a vm option is found in the unsupported_options array with index less than the info_idx, - // vm will exit with an error message. Otherwise, it will print an informational message if - // -Xlog:cds is enabled. - uint info_idx = 1; + // If a vm option is found in the unsupported_options array, vm will exit with an error message. SystemProperty* sp = system_properties(); while (sp != NULL) { for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) { if (strcmp(sp->key(), unsupported_properties[i]) == 0) { - if (i < info_idx) { - vm_exit_during_initialization( - "Cannot use the following option when dumping the shared archive", unsupported_options[i]); - } else { - log_info(cds)("Info: the %s option is ignored when dumping the shared archive", - unsupported_options[i]); - } + vm_exit_during_initialization( + "Cannot use the following option when dumping the shared archive", unsupported_options[i]); } } sp = sp->next(); @@ -1485,6 +1473,20 @@ vm_exit_during_initialization("Dumping the shared archive is not supported with an exploded module build"); } } + +bool Arguments::check_unsupported_cds_runtime_properties() { + assert(UseSharedSpaces, "this function is only used with -Xshare:{on,auto}"); + assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be"); + for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) { + if (get_property(unsupported_properties[i]) != NULL) { + if (RequireSharedSpaces) { + warning("CDS is disabled when the %s option is specified.", unsupported_options[i]); + } + return true; + } + } + return false; +} #endif //=========================================================================================================== @@ -3410,6 +3412,9 @@ if (UseSharedSpaces && patch_mod_javabase) { no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched."); } + if (UseSharedSpaces && !DumpSharedSpaces && check_unsupported_cds_runtime_properties()) { + FLAG_SET_DEFAULT(UseSharedSpaces, false); + } #endif #ifndef CAN_SHOW_REGISTERS_ON_ASSERT --- old/src/hotspot/share/runtime/arguments.hpp 2018-04-02 14:11:49.782934072 -0700 +++ new/src/hotspot/share/runtime/arguments.hpp 2018-04-02 14:11:49.510908439 -0700 @@ -697,6 +697,8 @@ static void check_unsupported_dumping_properties() NOT_CDS_RETURN; + static bool check_unsupported_cds_runtime_properties() NOT_CDS_RETURN; + static bool atojulong(const char *s, julong* result); }; --- old/src/hotspot/share/runtime/thread.cpp 2018-04-02 14:11:50.628013702 -0700 +++ new/src/hotspot/share/runtime/thread.cpp 2018-04-02 14:11:50.359988447 -0700 @@ -3891,6 +3891,11 @@ // cache the system and platform class loaders SystemDictionary::compute_java_loaders(CHECK_JNI_ERR); + if (DumpSharedSpaces) { + // capture the module path info from the ModuleEntryTable + ClassLoader::initialize_module_path(); + } + #if INCLUDE_JVMCI if (force_JVMCI_intialization) { JVMCIRuntime::force_initialization(CHECK_JNI_ERR); --- old/test/hotspot/jtreg/runtime/appcds/JarBuilder.java 2018-04-02 14:11:51.526098327 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/JarBuilder.java 2018-04-02 14:11:51.254072695 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,11 @@ */ import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import java.io.File; +import java.nio.file.Path; import java.util.ArrayList; import sun.tools.jar.Main; @@ -145,6 +147,21 @@ } } + public static void createModularJar(String jarPath, + String classesDir, + String mainClass) throws Exception { + ArrayList argList = new ArrayList(); + argList.add("--create"); + argList.add("--file=" + jarPath); + if (mainClass != null) { + argList.add("--main-class=" + mainClass); + } + argList.add("-C"); + argList.add(classesDir); + argList.add("."); + createJar(argList); + } + private static void createJar(ArrayList args) { if (DEBUG) printIterable("createJar args: ", args); @@ -190,6 +207,23 @@ output.shouldHaveExitValue(0); } + public static void compileModule(Path src, + Path dest, + String modulePathArg // arg to --module-path + ) throws Exception { + boolean compiled = false; + if (modulePathArg == null) { + compiled = CompilerUtils.compile(src, dest); + } else { + compiled = CompilerUtils.compile(src, dest, + "--module-path", modulePathArg); + } + if (!compiled) { + throw new RuntimeException("module did not compile"); + } + } + + public static void signJar() throws Exception { String keyTool = JDKToolFinder.getJDKTool("keytool"); String jarSigner = JDKToolFinder.getJDKTool("jarsigner"); --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/CheckUnsupportedDumpingOptions.java 2018-04-02 14:11:52.246166178 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/CheckUnsupportedDumpingOptions.java 2018-04-02 14:11:51.957138943 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,20 +40,15 @@ public class CheckUnsupportedDumpingOptions { private static final String[] jigsawOptions = { - "-m", "--limit-modules", - "--module-path", "--upgrade-module-path", "--patch-module" }; private static final String[] optionValues = { "mymod", - "mymod", - "mydir", ".", "java.naming=javax.naming.spi.NamingManger" }; - private static final int infoIdx = 1; public static void main(String[] args) throws Exception { String source = "package javax.naming.spi; " + @@ -71,31 +66,11 @@ String appClasses[] = {"Hello"}; for (int i = 0; i < jigsawOptions.length; i++) { OutputAnalyzer output; - if (i == 5) { - // --patch-module - output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables", - jigsawOptions[i] + optionValues[i] + appJar); - } else { - output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables", - jigsawOptions[i], optionValues[i]); - } - if (i < infoIdx) { - output.shouldContain("Cannot use the following option " + - "when dumping the shared archive: " + jigsawOptions[i]) - .shouldHaveExitValue(1); - } else { - output.shouldContain("Info: the " + jigsawOptions[i] + - " option is ignored when dumping the shared archive"); - if (optionValues[i].equals("mymod")) { - // java will throw FindException for a module - // which cannot be found during init_phase2() of vm init - output.shouldHaveExitValue(1) - .shouldContain("java.lang.module.FindException: Module mymod not found"); - } else { - output.shouldHaveExitValue(0); - } - } + output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables", + jigsawOptions[i], optionValues[i]); + output.shouldContain("Cannot use the following option " + + "when dumping the shared archive: " + jigsawOptions[i]) + .shouldHaveExitValue(1); } } } - --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/JigsawOptionsCombo.java 2018-04-02 14:11:52.944231956 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/JigsawOptionsCombo.java 2018-04-02 14:11:52.670206135 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,8 +69,7 @@ private ArrayList testCaseTable = new ArrayList(); public static String infoDuringDump(String option) { - return "Info: the " + option + - " option is ignored when dumping the shared archive"; + return "Cannot use the following option when dumping the shared archive: " + option; } public void runTests() throws Exception { @@ -78,7 +77,7 @@ testCaseTable.add(new TestCase( "basic: Basic dump and execute, to verify the test plumbing works", "", "", 0, - "", "", 0) ); + "", "", 0, true) ); String bcpArg = "-Xbootclasspath/a:" + TestCommon.getTestJar("hello_more.jar"); @@ -86,51 +85,50 @@ testCaseTable.add(new TestCase( "Xbootclasspath/a: is OK for both dump and run time", bcpArg, "", 0, - bcpArg, "", 0) ); + bcpArg, "", 0, true) ); testCaseTable.add(new TestCase( "module-path-01: --module-path is ignored for dump time", - "--module-path mods", - infoDuringDump("--module-path"), 0, - null, null, 0) ); + "--module-path mods", "", 0, + null, null, 0, true) ); testCaseTable.add(new TestCase( "module-path-02: --module-path is ok for run time", "", "", 0, - "--module-path mods", "", 0) ); + "--module-path mods", "", 0, true) ); testCaseTable.add(new TestCase( "add-modules-01: --add-modules is ok at dump time", "--add-modules java.management", "", 0, - null, null, 0) ); + null, null, 0, true) ); testCaseTable.add(new TestCase( "add-modules-02: --add-modules is ok at run time", "", "", 0, - "--add-modules java.management", "", 0) ); + "--add-modules java.management", "", 0, true) ); testCaseTable.add(new TestCase( "limit-modules-01: --limit-modules is ignored at dump time", "--limit-modules java.base", - infoDuringDump("--limit-modules"), 0, - null, null, 0) ); + infoDuringDump("--limit-modules"), 1, + null, null, 0, true) ); testCaseTable.add(new TestCase( "limit-modules-02: --limit-modules is ok at run time", "", "", 0, - "--limit-modules java.base", "", 0) ); + "--limit-modules java.base", "", 0, false) ); testCaseTable.add(new TestCase( "upgrade-module-path-01: --upgrade-module-path is ignored at dump time", "--upgrade-module-path mods", - infoDuringDump("--upgrade-module-path"), 0, - null, null, 0) ); + infoDuringDump("--upgrade-module-path"), 1, + null, null, 0, true) ); testCaseTable.add(new TestCase( "-upgrade-module-path-module-path-02: --upgrade-module-path is ok at run time", "", "", 0, - "--upgrade-module-path mods", "", 0) ); + "--upgrade-module-path mods", "", 0, false) ); for (TestCase tc : testCaseTable) tc.execute(); } @@ -145,6 +143,7 @@ String runTimeArgs; String runTimeExpectedOutput; int runTimeExpectedExitValue; + boolean sharingOn; private String appJar = TestCommon.getTestJar("hello.jar"); private String appClasses[] = {"Hello"}; @@ -152,7 +151,8 @@ public TestCase(String description, String dumpTimeArgs, String dumpTimeExpectedOutput, int dumpTimeExpectedExitValue, - String runTimeArgs, String runTimeExpectedOutput, int runTimeExpectedExitValue) { + String runTimeArgs, String runTimeExpectedOutput, int runTimeExpectedExitValue, + boolean sharingOn) { this.description = description; this.dumpTimeArgs = dumpTimeArgs; @@ -161,6 +161,7 @@ this.runTimeArgs = runTimeArgs; this.runTimeExpectedOutput = runTimeExpectedOutput; this.runTimeExpectedExitValue = runTimeExpectedExitValue; + this.sharingOn = sharingOn; } @@ -183,7 +184,13 @@ OutputAnalyzer execOutput = TestCommon.exec(appJar, getRunOptions()); if (runTimeExpectedExitValue == 0) { - TestCommon.checkExec(execOutput, runTimeExpectedOutput, "Hello World"); + if (sharingOn) { + TestCommon.checkExec(execOutput, runTimeExpectedOutput, "Hello World"); + } else { + execOutput.shouldHaveExitValue(0) + .shouldContain(runTimeExpectedOutput) + .shouldContain("Hello World"); + } } else { execOutput.shouldMatch(dumpTimeExpectedOutput); execOutput.shouldHaveExitValue(dumpTimeExpectedExitValue); --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java 2018-04-02 14:11:53.654298864 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java 2018-04-02 14:11:53.368271912 -0700 @@ -86,19 +86,20 @@ "--patch-module=java.naming=" + moduleJar, "-Xlog:class+load", "PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello"); - TestCommon.checkDump(output, "Loading classes to share"); + output.shouldHaveExitValue(1) + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); String classPath = appJar + File.pathSeparator + classDir; System.out.println("classPath: " + classPath); - TestCommon.run( + output = TestCommon.execCommon( "-XX:+UnlockDiagnosticVMOptions", "-cp", classPath, "--patch-module=java.naming=" + moduleJar, "-Xlog:class+load", - "PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello") - .assertNormalExit( - "I pass!", - "Hello!", - "Hello source: shared objects file"); + "PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello"); + output.shouldHaveExitValue(0) + .shouldContain("CDS is disabled") + .shouldContain("I pass!") + .shouldContain("Hello!"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java 2018-04-02 14:11:54.379367186 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java 2018-04-02 14:11:54.095340423 -0700 @@ -70,14 +70,17 @@ "-Xlog:class+load", "-Xlog:class+path=info", "PatchMain", "javax.naming.myspi.NamingManager"); - TestCommon.checkDump(output, "Preload Warning: Cannot find javax/naming/myspi/NamingManager"); + output.shouldHaveExitValue(1) + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); - TestCommon.run( + output = TestCommon.execCommon( "-XX:+UnlockDiagnosticVMOptions", "--patch-module=java.naming=" + moduleJar, "-Xlog:class+load", "-Xlog:class+path=info", - "PatchMain", "javax.naming.myspi.NamingManager") - .assertNormalExit("I pass!"); + "PatchMain", "javax.naming.myspi.NamingManager"); + output.shouldHaveExitValue(0) + .shouldContain("CDS is disabled") + .shouldContain("I pass!"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java 2018-04-02 14:11:55.125437487 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java 2018-04-02 14:11:54.837410347 -0700 @@ -62,71 +62,33 @@ JarBuilder.build("javanaming", "javax/naming/spi/NamingManager"); moduleJar = TestCommon.getTestJar("javanaming.jar"); - // Case 1: --patch-module specified for dump time and run time + // Case 1: --patch-module specified for dump time System.out.println("Case 1: --patch-module specified for dump time and run time"); OutputAnalyzer output = TestCommon.dump(null, TestCommon.list("javax/naming/spi/NamingManager"), "--patch-module=java.naming=" + moduleJar, "PatchMain", "javax.naming.spi.NamingManager"); - TestCommon.checkDump(output, "Loading classes to share"); + output.shouldHaveExitValue(1) + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); - // javax.naming.spi.NamingManager is not patched at runtime - TestCommon.run( - "-XX:+UnlockDiagnosticVMOptions", - "--patch-module=java.naming2=" + moduleJar, - "-Xlog:class+path=info", - "PatchMain", "javax.naming.spi.NamingManager") - .assertNormalExit(o -> o.shouldNotContain("I pass!")); - - // Case 2: --patch-module specified for dump time but not for run time - System.out.println("Case 2: --patch-module specified for dump time but not for run time"); + // Case 2: --patch-module specified for run time but not for dump time + System.out.println("Case 2: --patch-module specified for run time but not for dump time"); output = TestCommon.dump(null, TestCommon.list("javax/naming/spi/NamingManager"), - "--patch-module=java.naming=" + moduleJar, - "PatchMain", "javax.naming.spi.NamingManager"); - TestCommon.checkDump(output, "Loading classes to share"); - - // javax.naming.spi.NamingManager is not patched at runtime - TestCommon.run( - "-XX:+UnlockDiagnosticVMOptions", - "-Xlog:class+path=info", - "PatchMain", "javax.naming.spi.NamingManager") - .assertNormalExit(o -> o.shouldNotContain("I pass!")); - - // Case 3: --patch-module specified for run time but not for dump time - System.out.println("Case 3: --patch-module specified for run time but not for dump time"); - output = - TestCommon.dump(null, - TestCommon.list("javax/naming/spi/NamingManager"), - "PatchMain", "javax.naming.spi.NamingManager"); - TestCommon.checkDump(output, "Loading classes to share"); - - // javax.naming.spi.NamingManager is patched at runtime - TestCommon.run( - "-XX:+UnlockDiagnosticVMOptions", - "--patch-module=java.naming=" + moduleJar, - "-Xlog:class+path=info", - "PatchMain", "javax.naming.spi.NamingManager") - .assertNormalExit("I pass!"); - - // Case 4: mismatched --patch-module entry counts between dump time and run time - System.out.println("Case 4: mismatched --patch-module entry counts between dump time and run time"); - output = - TestCommon.dump(null, - TestCommon.list("javax/naming/spi/NamingManager"), - "--patch-module=java.naming=" + moduleJar, "PatchMain", "javax.naming.spi.NamingManager"); TestCommon.checkDump(output, "Loading classes to share"); // javax.naming.spi.NamingManager is patched at runtime - TestCommon.run( + output = TestCommon.execCommon( "-XX:+UnlockDiagnosticVMOptions", "--patch-module=java.naming=" + moduleJar, "--patch-module=java.naming2=" + moduleJar, "-Xlog:class+path=info", - "PatchMain", "javax.naming.spi.NamingManager") - .assertNormalExit("I pass!"); + "PatchMain", "javax.naming.spi.NamingManager"); + output.shouldHaveExitValue(0) + .shouldContain("CDS is disabled") + .shouldContain("I pass!"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchDir.java 2018-04-02 14:11:55.839504772 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchDir.java 2018-04-02 14:11:55.569479328 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ "--patch-module=java.naming=" + moduleJar, "-Xlog:class+load", "PatchMain", "javax.naming.spi.NamingManager") - .shouldContain("Loading classes to share") - .shouldHaveExitValue(0); + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module") + .shouldHaveExitValue(1); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java 2018-04-02 14:11:56.508567817 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java 2018-04-02 14:11:56.240542561 -0700 @@ -62,7 +62,8 @@ TestCommon.dump(null, null, "--patch-module=java.base=" + moduleJar, "PatchMain", "java.lang.NewClass"); - TestCommon.checkDump(output, "Loading classes to share"); + output.shouldHaveExitValue(1) + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); TestCommon.run( "-XX:+UnlockDiagnosticVMOptions", --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java 2018-04-02 14:11:57.207633689 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java 2018-04-02 14:11:56.935608056 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,14 +68,17 @@ "-Xlog:class+load", "-Xlog:class+path=info", "PatchMain", "javax.naming.spi.NamingManager"); - TestCommon.checkDump(output, "Loading classes to share"); + output.shouldHaveExitValue(1) + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); - TestCommon.run( + output = TestCommon.execCommon( "-XX:+UnlockDiagnosticVMOptions", "--patch-module=java.naming=" + moduleJar, "-Xlog:class+load", "-Xlog:class+path=info", - "PatchMain", "javax.naming.spi.NamingManager") - .assertNormalExit("I pass!"); + "PatchMain", "javax.naming.spi.NamingManager"); + output.shouldHaveExitValue(0) + .shouldContain("CDS is disabled") + .shouldContain("I pass!"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java 2018-04-02 14:11:57.932702011 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java 2018-04-02 14:11:57.639674399 -0700 @@ -88,18 +88,20 @@ "--patch-module=java.naming=" + moduleJar, "-Xlog:class+load", "PatchMain", "javax.naming.Reference", "mypackage.MyReference"); - TestCommon.checkDump(output, "Loading classes to share"); + output.shouldHaveExitValue(1) + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); String classPath = appJar + File.pathSeparator + classDir; System.out.println("classPath: " + classPath); - TestCommon.run( + output = TestCommon.execCommon( "-XX:+UnlockDiagnosticVMOptions", "-cp", classPath, "--patch-module=java.naming=" + moduleJar, "-Xlog:class+load", - "PatchMain", "javax.naming.Reference", "mypackage.MyReference") - .assertNormalExit( - "I pass!", - "MyReference source: file:"); + "PatchMain", "javax.naming.Reference", "mypackage.MyReference"); + output.shouldHaveExitValue(0) + .shouldContain("CDS is disabled") + .shouldContain("MyReference source: file:") + .shouldContain("I pass!"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java 2018-04-02 14:11:58.622767034 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java 2018-04-02 14:11:58.341740554 -0700 @@ -87,14 +87,17 @@ "-Xlog:class+load", "-Xlog:class+path=info", "PatchMain", "javax.naming.spi.NamingManager"); - TestCommon.checkDump(output, "Loading classes to share"); + output.shouldHaveExitValue(1) + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); - TestCommon.run( + output = TestCommon.execCommon( "-XX:+UnlockDiagnosticVMOptions", "--patch-module=java.naming=" + moduleJar2 + File.pathSeparator + moduleJar, "-Xlog:class+load", "-Xlog:class+path=info", - "PatchMain", "javax.naming.spi.NamingManager") - .assertNormalExit("I pass"); + "PatchMain", "javax.naming.spi.NamingManager"); + output.shouldHaveExitValue(0) + .shouldContain("CDS is disabled") + .shouldContain("I pass!"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java 2018-04-02 14:11:59.360836581 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java 2018-04-02 14:11:59.072809441 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,16 +147,22 @@ public static void testBootAppendExcludedModuleClassWithoutAppCDS() throws Exception { CDSOptions opts = (new CDSOptions()) .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar, + "-Xlog:class+load=info", "--limit-modules", "java.base") .setArchiveName(testArchiveName) + .setUseVersion(false) .addSuffix(MAIN_CLASS, "Test #3", BOOT_APPEND_MODULE_CLASS, "true", "BOOT"); - CDSTestUtils.runWithArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.runWithArchive(opts); + output.shouldHaveExitValue(0); + if (!TestCommon.isUnableToMap(output)) + output.shouldMatch(".class.load. sun.nio.cs.ext.MyClass source:.*bootAppend.jar"); } // Test #4: A shared class in excluded package that's archived from // -Xbootclasspath/a - // - should be loaded from the archive by the bootstrap classloader + // - should be loaded from the jar since AppCDS will be disabled with + // the --limit-modules option public static void testBootAppendExcludedModuleClassWithAppCDS() throws Exception { OutputAnalyzer output = TestCommon.exec( appJar, @@ -165,9 +171,9 @@ "-XX:+TraceClassLoading", MAIN_CLASS, "Test #4", BOOT_APPEND_MODULE_CLASS, "true", "BOOT"); - TestCommon.checkExec(output); + output.shouldHaveExitValue(0); if (!TestCommon.isUnableToMap(output)) - output.shouldContain("[class,load] sun.nio.cs.ext.MyClass source: shared objects file"); + output.shouldMatch(".class.load. sun.nio.cs.ext.MyClass source:.*bootAppend.jar"); } @@ -231,11 +237,16 @@ CDSOptions opts = (new CDSOptions()) .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar, + "-Xlog:class+load=info", "--limit-modules", "java.base") .setArchiveName(testArchiveName) + .setUseVersion(false) .addSuffix(MAIN_CLASS, "Test #9", APP_MODULE_CLASS, "true", "BOOT"); - CDSTestUtils.runWithArchiveAndCheck(opts); + OutputAnalyzer output = CDSTestUtils.runWithArchive(opts); + output.shouldHaveExitValue(0); + if (!TestCommon.isUnableToMap(output)) + output.shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar"); } // Test #10: A shared class in excluded package defined in jimage app module @@ -248,9 +259,9 @@ "--limit-modules", "java.base", MAIN_CLASS, "Test #10", APP_MODULE_CLASS, "true", "BOOT"); - TestCommon.checkExec(output); + output.shouldHaveExitValue(0); if (!TestCommon.isUnableToMap(output)) - output.shouldContain("[class,load] com.sun.tools.javac.Main2 source: shared objects file"); + output.shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java 2018-04-02 14:12:00.062902736 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java 2018-04-02 14:11:59.791877198 -0700 @@ -89,13 +89,19 @@ argsList.add("useAppLoader"); opts = new String[argsList.size()]; opts = argsList.toArray(opts); - TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION); + OutputAnalyzer output = TestCommon.execCommon(opts); + output.shouldHaveExitValue(0) + .shouldContain(EXPECTED_EXCEPTION) + .shouldContain("CDS is disabled"); // case 4: load class in bootclasspath using boot loader with '--limit-modules java.base' argsList.remove(argsList.size() - 1); argsList.add("useBootLoader"); opts = new String[argsList.size()]; opts = argsList.toArray(opts); - TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION); + output = TestCommon.execCommon(opts); + output.shouldHaveExitValue(0) + .shouldContain(EXPECTED_EXCEPTION) + .shouldContain("CDS is disabled"); } } --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsHelper.java 2018-04-02 14:12:00.783970681 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsHelper.java 2018-04-02 14:12:00.496943635 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,11 +65,22 @@ // Make sure we got the expected defining ClassLoader testLoader(clazz, expectedLoaders[i]); - // Make sure the class is in the shared space - if (!wb.isSharedClass(clazz)) { - throw new RuntimeException(clazz.getName() + - ".class should be in the shared space. " + - "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName()); + // Make sure the class is not in the shared space + // because CDS is disabled with --limit-modules during run time. + if (excludeModIdx != -1) { + if (wb.isSharedClass(clazz)) { + throw new RuntimeException(clazz.getName() + + ".class should not be in the shared space. " + + "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName()); + } + } else { + // class should be in the shared space if --limit-modules + // isn't specified during run time + if (!wb.isSharedClass(clazz)) { + throw new RuntimeException(clazz.getName() + + ".class should be in the shared space. " + + "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName()); + } } } clazz = null; --- old/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsTests.java 2018-04-02 14:12:01.478036082 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsTests.java 2018-04-02 14:12:01.212011015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,7 @@ "LimitModsHelper", BOOT_ARCHIVE_CLASS, PLATFORM_ARCHIVE_CLASS, APP_ARCHIVE_CLASS, Integer.toString(excludeModIdx)); // last 4 args passed to test - TestCommon.checkExec(output); + output.shouldHaveExitValue(0); limitMods = null; } } --- old/test/hotspot/jtreg/runtime/appcds/test-classes/JvmtiApp.java 2018-04-02 14:12:02.189103084 -0700 +++ new/test/hotspot/jtreg/runtime/appcds/test-classes/JvmtiApp.java 2018-04-02 14:12:01.920077735 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,9 @@ import sun.hotspot.WhiteBox; public class JvmtiApp { - static Class forname() { + static Class forname(String cn) { try { - return Class.forName("Hello"); + return Class.forName(cn); } catch (Throwable t) { return null; } @@ -40,9 +40,14 @@ // See ../JvmtiAddPath.java for how the classpaths are configured. public static void main(String args[]) { + String cn = "Hello"; + if (args.length >= 3) { + cn = args[args.length - 1]; + } + if (args[0].equals("noadd")) { - if (forname() != null) { - failed("Hello class was loaded unexpectedly"); + if (forname(cn) != null) { + failed(cn + " class was loaded unexpectedly"); } // We use -verbose:class to verify that Extra.class IS loaded by AppCDS if // the boot classpath HAS NOT been appended. @@ -54,39 +59,41 @@ if (args[0].equals("bootonly")) { wb.addToBootstrapClassLoaderSearch(args[1]); - Class cls = forname(); + Class cls = forname(cn); if (cls == null) { - failed("Cannot find Hello class"); + failed("Cannot find " + cn + " class"); } if (cls.getClassLoader() != null) { failed("Hello class not loaded by boot classloader"); } } else if (args[0].equals("apponly")) { wb.addToSystemClassLoaderSearch(args[1]); - Class cls = forname(); + Class cls = forname(cn); if (cls == null) { - failed("Cannot find Hello class"); + failed("Cannot find " + cn + " class"); } if (cls.getClassLoader() != JvmtiApp.class.getClassLoader()) { - failed("Hello class not loaded by app classloader"); + failed(cn + " class not loaded by app classloader"); } } else if (args[0].equals("noadd-appcds")) { - Class cls = forname(); + cn = (args.length == 1) ? "Hello" : args[1]; + Class cls = forname(cn); if (cls == null) { - failed("Cannot find Hello class"); + failed("Cannot find " + cn + " class"); } if (cls.getClassLoader() != JvmtiApp.class.getClassLoader()) { - failed("Hello class not loaded by app classloader"); + failed(cn + " class not loaded by app classloader"); } } else if (args[0].equals("appandboot")) { wb.addToBootstrapClassLoaderSearch(args[1]); wb.addToSystemClassLoaderSearch(args[2]); - Class cls = forname(); + cn = (args.length == 3) ? "Hello" : args[3]; + Class cls = forname(cn); if (cls == null) { - failed("Cannot find Hello class"); + failed("Cannot find " + cn + " class"); } if (cls.getClassLoader() != null) { - failed("Hello class not loaded by boot classloader"); + failed(cn + " class not loaded by boot classloader"); } } else { failed("unknown option " + args[0]); @@ -102,4 +109,4 @@ class ExtraClass { static void doit() {} -} \ No newline at end of file +} --- old/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java 2018-04-02 14:12:02.978177437 -0700 +++ new/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java 2018-04-02 14:12:02.677149072 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,8 @@ "-Xlog:class+path=info", "-version"); new OutputAnalyzer(pb.start()) - .shouldContain("ro space:"); // Make sure archive got created. + // --patch-module is not supported during CDS dumping + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); // Case 2: Test that directory in --patch-module is supported for CDS dumping // Create a class file in the module java.base. @@ -73,7 +74,8 @@ "-Xlog:class+path=info", "-version"); new OutputAnalyzer(pb.start()) - .shouldContain("ro space:"); // Make sure archive got created. + // --patch-module is not supported during CDS dumping + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); // Case 3a: Test CDS dumping with jar file in --patch-module BasicJarBuilder.build("javanaming", "javax/naming/spi/NamingManager"); @@ -87,7 +89,8 @@ "-Xlog:class+path=info", "PatchModuleMain", "javax.naming.spi.NamingManager"); new OutputAnalyzer(pb.start()) - .shouldContain("ro space:"); // Make sure archive got created. + // --patch-module is not supported during CDS dumping + .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module"); // Case 3b: Test CDS run with jar file in --patch-module pb = ProcessTools.createJavaProcessBuilder( --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddModules.java 2018-04-02 14:12:03.422219279 -0700 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules jdk.compiler + * jdk.jartool/sun.tools.jar + * jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils jdk.testlibrary.* + * @run main AddModules + * @summary sanity test the --add-modules option + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +public class AddModules { + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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("mods"); + + // the module name of the test module + private static final String MAIN_MODULE1 = "com.greetings"; + private static final String MAIN_MODULE2 = "com.hello"; + private static final String SUB_MODULE = "org.astro"; + + // the module main class + private static final String MAIN_CLASS1 = "com.greetings.Main"; + private static final String MAIN_CLASS2 = "com.hello.Main"; + private static final String APP_CLASS = "org.astro.World"; + + private static Path moduleDir = null; + private static Path subJar = null; + private static Path mainJar1 = null; + private static Path mainJar2 = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE), + MODS_DIR.resolve(SUB_MODULE), + null); + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE1), + MODS_DIR.resolve(MAIN_MODULE1), + MODS_DIR.toString()); + + JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE2), + MODS_DIR.resolve(MAIN_MODULE2), + MODS_DIR.toString()); + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + subJar = moduleDir.resolve(SUB_MODULE + ".jar"); + String classes = MODS_DIR.resolve(SUB_MODULE).toString(); + JarBuilder.createModularJar(subJar.toString(), classes, null); + + mainJar1 = moduleDir.resolve(MAIN_MODULE1 + ".jar"); + classes = MODS_DIR.resolve(MAIN_MODULE1).toString(); + JarBuilder.createModularJar(mainJar1.toString(), classes, MAIN_CLASS1); + + mainJar2 = moduleDir.resolve(MAIN_MODULE2 + ".jar"); + classes = MODS_DIR.resolve(MAIN_MODULE2).toString(); + JarBuilder.createModularJar(mainJar2.toString(), classes, MAIN_CLASS2); + + } + + public static void main(String... args) throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + String appClasses[] = {MAIN_CLASS1, MAIN_CLASS2, APP_CLASS}; + // create an archive with the classes in the modules built in the + // previous step + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", moduleDir.toString(), + "--add-modules", + MAIN_MODULE1 + "," + MAIN_MODULE2); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace"}; + + // run the com.greetings module with the archive with the --module-path + // the same as the one during dump time. + // The classes should be loaded from the archive. + output = TestCommon.execModule(prefix, + null, // --upgrade-module-path + moduleDir.toString(), // --module-path + MAIN_MODULE1); // -m + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.greetings.Main source: shared objects file", + "[class,load] org.astro.World source: shared objects file"); + + // run the com.hello module with the archive with the --module-path + // the same as the one during dump time. + // The classes should be loaded from the archive. + output = TestCommon.execModule(prefix, + null, // --upgrade-module-path + moduleDir.toString(), // --module-path + MAIN_MODULE2); // -m + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.hello.Main source: shared objects file", + "[class,load] org.astro.World source: shared objects file"); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java 2018-04-02 14:12:04.156288449 -0700 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules jdk.compiler + * jdk.jartool/sun.tools.jar + * jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils jdk.testlibrary.* + * @run main AddOpens + * @summary sanity test the --add-opens option + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +public class AddOpens { + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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("mods"); + + // the module name of the test module + private static final String TEST_MODULE1 = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path moduleDir2 = null; + private static Path destJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1), + MODS_DIR.resolve(TEST_MODULE1), + MODS_DIR.toString()); + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2"); + + Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar"); + destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE1).toString(); + JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS); + Files.copy(srcJar, destJar); + + } + + public static void main(String... args) throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + String appClasses[] = {MAIN_CLASS}; + // create an archive with both -cp and --module-path in the command line. + // Only the class in the modular jar in the --module-path will be archived; + // the class in the modular jar in the -cp won't be archived. + OutputAnalyzer output = TestCommon.createArchive( + destJar.toString(), appClasses, + "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + + // run with the archive using the same command line as in dump time + // plus the "--add-opens java.base/java.lang=com.simple" option. + // The main class should be loaded from the archive. + // The setaccessible(true) on the ClassLoader.defineClass method should + // be successful. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--add-opens", "java.base/java.lang=" + TEST_MODULE1, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1, "with_add_opens"); + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.simple.Main source: shared objects file", + "method.setAccessible succeeded!"); + + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddReads.java 2018-04-02 14:12:04.892357808 -0700 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules jdk.compiler + * jdk.jartool/sun.tools.jar + * jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils jdk.testlibrary.* + * @run main AddReads + * @summary sanity test the --add-reads option + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.Asserts; + +public class AddReads { + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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("mods"); + + // the module name of the test module + private static final String MAIN_MODULE = "com.norequires"; + private static final String SUB_MODULE = "org.astro"; + + // the module main class + private static final String MAIN_CLASS = "com.norequires.Main"; + private static final String APP_CLASS = "org.astro.World"; + + private static Path moduleDir = null; + private static Path subJar = null; + private static Path mainJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE), + MODS_DIR.resolve(SUB_MODULE), + null); + + Asserts.assertTrue(CompilerUtils + .compile(SRC_DIR.resolve(MAIN_MODULE), + MODS_DIR.resolve(MAIN_MODULE), + "-cp", MODS_DIR.resolve(SUB_MODULE).toString(), + "--add-reads", "com.norequires=ALL-UNNAMED")); + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + subJar = moduleDir.resolve(SUB_MODULE + ".jar"); + String classes = MODS_DIR.resolve(SUB_MODULE).toString(); + JarBuilder.createModularJar(subJar.toString(), classes, null); + + mainJar = moduleDir.resolve(MAIN_MODULE + ".jar"); + classes = MODS_DIR.resolve(MAIN_MODULE).toString(); + JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS); + } + + public static void main(String... args) throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + String appClasses[] = {MAIN_CLASS, APP_CLASS}; + // create an archive with the classes in the modules built in the + // previous step + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", moduleDir.toString(), + "--add-modules", SUB_MODULE, + "--add-reads", "com.norequires=org.astro", + "-m", MAIN_MODULE); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace", + "--add-modules", SUB_MODULE, + "--add-reads", "com.norequires=org.astro"}; + + // run the com.norequires module with the archive with the same args + // used during dump time. + // The classes should be loaded from the archive. + output = TestCommon.execModule(prefix, + null, // --upgrade-module-path + moduleDir.toString(), // --module-path + MAIN_MODULE); // -m + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.norequires.Main source: shared objects file", + "[class,load] org.astro.World source: shared objects file"); + + // create an archive with -cp pointing to the jar file containing the + // org.astro module and --module-path pointing to the main module + output = TestCommon.createArchive( + subJar.toString(), appClasses, + "--module-path", moduleDir.toString(), + "--add-modules", SUB_MODULE, + "--add-reads", "com.norequires=org.astro", + "-m", MAIN_MODULE); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + // run the com.norequires module with the archive with the sub-module + // in the -cp and with -add-reads=com.norequires=ALL-UNNAMED + // The main class should be loaded from the archive. + // The org.astro.World should be loaded from the jar. + String prefix2[] = {"-cp", subJar.toString(), "-Xlog:class+load=trace", + "--add-reads", "com.norequires=ALL-UNNAMED"}; + output = TestCommon.execModule(prefix2, + null, // --upgrade-module-path + moduleDir.toString(), // --module-path + MAIN_MODULE); // -m + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.norequires.Main source: shared objects file"); + output.shouldMatch(".class.load. org.astro.World source:.*org.astro.jar"); + + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java 2018-04-02 14:12:05.639428203 -0700 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules jdk.compiler + * jdk.jartool/sun.tools.jar + * jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils jdk.testlibrary.* + * @run main ExportModule + * @summary Tests involve exporting a module from the module path to a jar in the -cp. + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.compiler.CompilerUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.Asserts; + +public class ExportModule { + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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("mods"); + + // the module name of the test module + private static final String TEST_MODULE1 = "com.greetings"; + private static final String TEST_MODULE2 = "org.astro"; + + // unnamed module package name + private static final String PKG_NAME = "com.nomodule"; + + // the module main class + private static final String MAIN_CLASS = "com.greetings.Main"; + private static final String APP_CLASS = "org.astro.World"; + + // unnamed module main class + private static final String UNNAMED_MAIN = "com.nomodule.Main"; + + private static Path moduleDir = null; + private static Path moduleDir2 = null; + private static Path appJar = null; + private static Path appJar2 = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE2), + MODS_DIR.resolve(TEST_MODULE2), + null); + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1), + MODS_DIR.resolve(TEST_MODULE1), + MODS_DIR.toString()); + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + Path jar = moduleDir.resolve(TEST_MODULE2 + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE2).toString(); + JarBuilder.createModularJar(jar.toString(), classes, null); + + moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2"); + appJar = moduleDir2.resolve(TEST_MODULE1 + ".jar"); + classes = MODS_DIR.resolve(TEST_MODULE1).toString(); + JarBuilder.createModularJar(appJar.toString(), classes, MAIN_CLASS); + + // build a non-modular jar containing the main class which + // requires the org.astro package + boolean compiled + = CompilerUtils.compile(SRC_DIR.resolve(PKG_NAME), + MODS_DIR.resolve(PKG_NAME), + "--module-path", MODS_DIR.toString(), + "--add-modules", TEST_MODULE2, + "--add-exports", "org.astro/org.astro=ALL-UNNAMED"); + Asserts.assertTrue(compiled, "test package did not compile"); + + appJar2 = moduleDir2.resolve(PKG_NAME + ".jar"); + classes = MODS_DIR.resolve(PKG_NAME).toString(); + JarBuilder.createModularJar(appJar2.toString(), classes, null); + } + + public static void main(String... args) throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + String appClasses[] = {MAIN_CLASS, APP_CLASS}; + // create an archive with the class in the org.astro module built in the + // previous step and the main class from the modular jar in the -cp + // note: the main class is in the modular jar in the -cp which requires + // the module in the --module-path + OutputAnalyzer output = TestCommon.createArchive( + appJar.toString(), appClasses, + "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "--module-path", moduleDir.toString(), + "--add-modules", TEST_MODULE2, MAIN_CLASS); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + + // run it using the archive + // both the main class and the class from the org.astro module should + // be loaded from the archive + output = TestCommon.execCommon("-Xlog:class+load=trace", + "-cp", appJar.toString(), + "--module-path", moduleDir.toString(), + "--add-modules", TEST_MODULE2, MAIN_CLASS); + TestCommon.checkExecReturn(output, 0, true, + "[class,load] org.astro.World source: shared objects file", + "[class,load] com.greetings.Main source: shared objects file"); + + String appClasses2[] = {UNNAMED_MAIN, APP_CLASS}; + // create an archive with the main class from a non-modular jar in the + // -cp and the class from the org.astro module + // note: the org.astro package needs to be exported to "ALL-UNNAMED" + // module since the jar in the -cp is a non-modular jar and thus it is + // unnmaed. + output = TestCommon.createArchive( + appJar2.toString(), appClasses2, + "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "--module-path", moduleDir.toString(), + "--add-modules", TEST_MODULE2, + "--add-exports", "org.astro/org.astro=ALL-UNNAMED", + UNNAMED_MAIN); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + + // both the main class and the class from the org.astro module should + // be loaded from the archive + output = TestCommon.execCommon("-Xlog:class+load=trace", + "-cp", appJar2.toString(), + "--module-path", moduleDir.toString(), + "--add-modules", TEST_MODULE2, + "--add-exports", "org.astro/org.astro=ALL-UNNAMED", + UNNAMED_MAIN); + + TestCommon.checkExecReturn(output, 0, true, + "[class,load] org.astro.World source: shared objects file", + "[class,load] com.nomodule.Main source: shared objects file"); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java 2018-04-02 14:12:06.353495488 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary JvmtiEnv::AddToBootstrapClassLoaderSearch and JvmtiEnv::AddToSystemClassLoaderSearch should disable AppCDS + * @requires vm.cds + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules java.base/jdk.internal.misc + * java.management + * jdk.jartool/sun.tools.jar + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * @compile ../../test-classes/JvmtiApp.java + * @run main JvmtiAddPath + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.process.OutputAnalyzer; +import sun.hotspot.WhiteBox; + +public class JvmtiAddPath { + static String use_whitebox_jar; + static String[] no_extra_matches = {}; + static String[] check_appcds_enabled = { + "[class,load] ExtraClass source: shared object" + }; + static String[] check_appcds_disabled = { + "[class,load] ExtraClass source: file:" + }; + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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("mods"); + + // the module name of the test module + private static final String TEST_MODULE1 = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path mainJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1), + MODS_DIR.resolve(TEST_MODULE1), + MODS_DIR.toString()); + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + + mainJar = moduleDir.resolve(TEST_MODULE1 + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE1).toString(); + JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS); + } + + static void run(String cp, String... args) throws Exception { + run(no_extra_matches, cp, args); + } + + static void run(String[] extra_matches, String cp, String... args) throws Exception { + String[] opts = {"-cp", cp, "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", use_whitebox_jar}; + opts = TestCommon.concat(opts, args); + TestCommon.run(opts).assertNormalExit(extra_matches); + } + + public static void main(String[] args) throws Exception { + buildTestModule(); + JarBuilder.build("jvmti_app", "JvmtiApp", "ExtraClass"); + JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox"); + + // In all the test cases below, appJar does not contain Hello.class. Instead, we + // append JAR file(s) that contain Hello.class to the boot classpath, the app + // classpath, or both, and verify that Hello.class is loaded by the expected ClassLoader. + String appJar = TestCommon.getTestJar("jvmti_app.jar"); // contains JvmtiApp.class + String addappJar = mainJar.toString(); // contains Main.class + String addbootJar = mainJar.toString(); // contains Main.class + String twoAppJars = appJar + File.pathSeparator + addappJar; + String modulePath = "--module-path=" + moduleDir.toString(); + String wbJar = TestCommon.getTestJar("WhiteBox.jar"); + use_whitebox_jar = "-Xbootclasspath/a:" + wbJar; + + OutputAnalyzer output = TestCommon.createArchive( + appJar, + TestCommon.list("JvmtiApp", "ExtraClass", MAIN_CLASS), + use_whitebox_jar, + "-Xlog:class+load=trace", + modulePath); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + + System.out.println("Test case 1: not adding module path - Hello.class should not be found"); + run(check_appcds_enabled, appJar, + "-Xlog:class+load", "JvmtiApp", "noadd", MAIN_CLASS); // appcds should be enabled + + System.out.println("Test case 2: add to boot classpath only - should find Hello.class in boot loader"); + run(check_appcds_disabled, appJar, + "-Xlog:class+load=trace", + modulePath, + "JvmtiApp", "bootonly", addbootJar, MAIN_CLASS); // appcds should be disabled + + System.out.println("Test case 3: add to app classpath only - should find Hello.class in app loader"); + run(appJar, modulePath, + "JvmtiApp", "apponly", addappJar, MAIN_CLASS); + + System.out.println("Test case 4: add to boot and app paths - should find Hello.class in boot loader"); + run(appJar, modulePath, + "JvmtiApp", "appandboot", addbootJar, addappJar, MAIN_CLASS); + + System.out.println("Test case 5: add to app using -cp, but add to boot using JVMTI - should find Hello.class in boot loader"); + run(appJar, modulePath, + "JvmtiApp", "bootonly", addappJar, MAIN_CLASS); + + System.out.println("Test case 6: add to app using AppCDS, but add to boot using JVMTI - should find Hello.class in boot loader"); + output = TestCommon.createArchive( + appJar, TestCommon.list("JvmtiApp", "ExtraClass"), + use_whitebox_jar, + "-Xlog:class+load=trace", + modulePath); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + run(twoAppJars, modulePath, + "JvmtiApp", "bootonly", addappJar, MAIN_CLASS); + + System.out.println("Test case 7: add to app using AppCDS, no JVMTI calls - should find Hello.class in app loader"); + run(twoAppJars, modulePath, + "JvmtiApp", "noadd-appcds", MAIN_CLASS); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java 2018-04-02 14:12:07.073563339 -0700 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules jdk.compiler + * jdk.jartool/sun.tools.jar + * jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils jdk.testlibrary.* + * @run main MainModuleOnly + * @summary Test some scenarios with a main modular jar specified in the --module-path and -cp options in the command line. + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +public class MainModuleOnly { + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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("mods"); + + // the module name of the test module + private static final String TEST_MODULE1 = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path moduleDir2 = null; + private static Path destJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1), + MODS_DIR.resolve(TEST_MODULE1), + MODS_DIR.toString()); + + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2"); + + Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar"); + destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE1).toString(); + JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS); + Files.copy(srcJar, destJar); + + } + + public static void main(String... args) throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + String appClasses[] = {MAIN_CLASS}; + // create an archive with both -cp and --module-path in the command line. + // Only the class in the modular jar in the --module-path will be archived; + // the class in the modular jar in the -cp won't be archived. + OutputAnalyzer output = TestCommon.createArchive( + destJar.toString(), appClasses, + "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + + // run with the archive using the same command line as in dump time. + // The main class should be loaded from the archive. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.simple.Main source: shared objects file"); + + // run with the archive with the main class name inserted before the -m. + // The main class name will be picked up before the module name. So the + // main class should be loaded from the jar in the -cp. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--module-path", moduleDir.toString(), + MAIN_CLASS, "-m", TEST_MODULE1); + output.shouldHaveExitValue(0) + .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar"); + + // run with the archive with exploded module. Since during dump time, we + // only archive classes from the modular jar in the --module-path, the + // main class should be loaded from the exploded module directory. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--module-path", MODS_DIR.toString(), + "-m", TEST_MODULE1 + "/" + MAIN_CLASS); + output.shouldHaveExitValue(0) + .shouldMatch(".class.load. com.simple.Main source:.*com.simple") + .shouldContain(MODS_DIR.toString()); + + // run with the archive with the --upgrade-module-path option. + // CDS will be disabled with this options and the main class will be + // loaded from the modular jar. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--upgrade-module-path", moduleDir.toString(), + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + output.shouldHaveExitValue(0) + .shouldMatch("CDS is disabled when the.*option is specified") + .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar"); + // run with the archive with the --limit-modules option. + // CDS will be disabled with this options and the main class will be + // loaded from the modular jar. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--limit-modules", "java.base," + TEST_MODULE1, + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + output.shouldHaveExitValue(0) + .shouldMatch("CDS is disabled when the.*option is specified") + .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar"); + // run with the archive with the --patch-module option. + // CDS will be disabled with this options and the main class will be + // loaded from the modular jar. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--patch-module", TEST_MODULE1 + "=" + MODS_DIR.toString(), + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + output.shouldHaveExitValue(0) + .shouldMatch("CDS is disabled when the.*option is specified") + .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar"); + // modify the timestamp of the jar file + (new File(destJar.toString())).setLastModified(System.currentTimeMillis() + 2000); + // run with the archive and the jar with modified timestamp. + // It should fail due to timestamp of the jar doesn't match the one + // used during dump time. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", destJar.toString(), + "--module-path", moduleDir.toString(), + "-m", TEST_MODULE1); + TestCommon.checkExecReturn(output, 1, true, + "A jar/jimage file is not the one used while building the shared archive file:"); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java 2018-04-02 14:12:07.796631472 -0700 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules jdk.compiler + * jdk.jartool/sun.tools.jar + * jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils jdk.testlibrary.* + * @run main ModulePathAndCP + * @summary 2 sets of tests: one with only --module-path in the command line; + * another with both -cp and --module-path in the command line. + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +public class ModulePathAndCP { + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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("mods"); + + // the module name of the test module + private static final String MAIN_MODULE = "com.greetings"; + private static final String APP_MODULE = "org.astro"; + + // the module main class + private static final String MAIN_CLASS = "com.greetings.Main"; + private static final String APP_CLASS = "org.astro.World"; + + private static Path moduleDir = null; + private static Path moduleDir2 = null; + private static Path subJar = null; + private static Path mainJar = null; + private static Path destJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(APP_MODULE), + MODS_DIR.resolve(APP_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()); + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2"); + subJar = moduleDir.resolve(APP_MODULE + ".jar"); + destJar = moduleDir2.resolve(APP_MODULE + ".jar"); + String classes = MODS_DIR.resolve(APP_MODULE).toString(); + JarBuilder.createModularJar(subJar.toString(), classes, null); + Files.copy(subJar, destJar); + + mainJar = moduleDir.resolve(MAIN_MODULE + ".jar"); + Path mainJar2 = moduleDir2.resolve(MAIN_MODULE + ".jar"); + classes = MODS_DIR.resolve(MAIN_MODULE).toString(); + JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS); + Files.copy(mainJar, mainJar2); + + } + + public static void main(String... args) throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + String appClasses[] = {MAIN_CLASS, APP_CLASS}; + // create an archive with the classes in the modules built in the + // previous step + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", moduleDir.toString(), + "-m", MAIN_MODULE); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace"}; + + // run with the archive with the --module-path the same as the one during + // dump time. The classes should be loaded from the archive. + output = TestCommon.execModule(prefix, + null, // --upgrade-module-path + moduleDir.toString(), // --module-path + MAIN_MODULE); // -m + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.greetings.Main source: shared objects file", + "[class,load] org.astro.World source: shared objects file"); + + // run with the archive with the --module-path different from the one during + // dump time. The classes should be loaded from the jar files. + output = TestCommon.execModule(prefix, + null, // --upgrade-module-path + moduleDir2.toString(), // --module-path + MAIN_MODULE); // -m + output.shouldHaveExitValue(0) + .shouldMatch(".class.load. com.greetings.Main source:.*com.greetings.jar") + .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar"); + + // create an archive with modular jar files in both -cp and --module-path + String jars = subJar.toString() + System.getProperty("path.separator") + + mainJar.toString(); + output = TestCommon.createArchive( jars, appClasses, + "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit", + "--module-path", moduleDir.toString(), + "-m", MAIN_MODULE); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + + // run with archive with the main class name specified before + // the module name with the -m option. Since the -m option was specified + // during dump time, the classes in the jar files after the -cp won't be + // archived. Therefore, the classes won't be loaded from the archive but + // will be loaded from the jar files. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", jars, + "--module-path", moduleDir.toString(), + MAIN_CLASS, "-m", MAIN_MODULE); + output.shouldHaveExitValue(0) + .shouldMatch(".class.load. com.greetings.Main source:.*com.greetings.jar") + .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar"); + // similar to the above case but without the main class name. The classes + // should be loaded from the archive. + output = TestCommon.execCommon( "-Xlog:class+load=trace", + "-cp", jars, + "--module-path", moduleDir.toString(), + "-m", MAIN_MODULE); + TestCommon.checkExecReturn(output, 0, true, + "[class,load] com.greetings.Main source: shared objects file", + "[class,load] org.astro.World source: shared objects file"); + + // create an archive with two modular jars in the --module-path + output = TestCommon.createArchive( + null, appClasses, + "--module-path", jars, + "-m", MAIN_MODULE); + TestCommon.checkExecReturn(output, 0, true, "Loading classes to share"); + + // run with the above archive but with the modular jar containing the + // org.astro module in a different location. + // The org.astro.World class should be loaded from the jar. + // The Main class should still be loaded from the archive. + jars = destJar.toString() + System.getProperty("path.separator") + + mainJar.toString(); + output = TestCommon.execModule(prefix, + null, // --upgrade-module-path + jars, // --module-path + MAIN_MODULE); // -m + output.shouldHaveExitValue(0) + .shouldContain("[class,load] com.greetings.Main source: shared objects file") + .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar"); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/com/greetings/Main.java 2018-04-02 14:12:08.528700454 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package com.greetings; +import org.astro.World; +public class Main { + public static void main(String[] args) { + System.out.format("Greetings %s!\n", World.name()); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/module-info.java 2018-04-02 14:12:09.258769247 -0700 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +module com.greetings { + requires org.astro; +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/com/hello/Main.java 2018-04-02 14:12:09.964835779 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package com.hello; +import org.astro.World; +public class Main { + public static void main(String[] args) { + System.out.format("Hello %s!\n", World.name()); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/module-info.java 2018-04-02 14:12:10.717906739 -0700 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +module com.hello { + requires org.astro; +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.nomodule/com/nomodule/Main.java 2018-04-02 14:12:11.436974496 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package com.nomodule; +import org.astro.World; +public class Main { + public static void main(String[] args) { + System.out.format("Greetings %s!\n", World.name()); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/com/norequires/Main.java 2018-04-02 14:12:12.179044420 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package com.norequires; +import org.astro.World; +public class Main { + public static void main(String[] args) { + System.out.format("Hello %s!\n", World.name()); + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/module-info.java 2018-04-02 14:12:12.899112271 -0700 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +module com.norequires { } --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/com/simple/Main.java 2018-04-02 14:12:13.623180499 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package com.simple; + +import java.lang.reflect.Method; + +public class Main { + public static void main(String[] args) throws Exception { + System.out.println("Hello World!"); + if (args.length > 0 && args[0].equals("with_add_opens")) { + Method method = ClassLoader.class.getDeclaredMethod("defineClass", + byte[].class, int.class, int.class); + method.setAccessible(true); + System.out.println("method.setAccessible succeeded!"); + } + } +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/module-info.java 2018-04-02 14:12:14.397253439 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +module com.simple { +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/module-info.java 2018-04-02 14:12:15.118321384 -0700 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +module org.astro { + exports org.astro; +} --- /dev/null 2018-02-08 21:21:41.723217456 -0800 +++ new/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/org/astro/World.java 2018-04-02 14:12:15.840389423 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.astro; +public class World { + public static String name() { + return "world"; + } +}