# HG changeset patch # User chegar # Date 1417616474 0 # Node ID 47f369e3c69c8465b5b820088e3f245a1705a16c # Parent 7ead528de130864f91cab35943fa91da38997636 8049367: Modular Run-Time Images Reviewed-by: chegar, dfuchs, ihse, joehw, mullan, psandoz, wetmore Contributed-by: alan.bateman@oracle.com, alex.buckley@oracle.com, bradford.wetmore@oracle.com, chris.hegarty@oracle.com, erik.joelsson@oracle.com, james.laskey@oracle.com, jonathan.gibbons@oracle.com, karen.kinnear@oracle.com, magnus.ihse.bursie@oracle.com, mandy.chung@oracle.com, mark.reinhold@oracle.com, paul.sandoz@oracle.com, sundararajan.athijegannathan@oracle.com diff -r 7ead528de130 -r 47f369e3c69c hotspot/make/bsd/makefiles/sa.make --- a/hotspot/make/bsd/makefiles/sa.make Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/make/bsd/makefiles/sa.make Wed Dec 03 14:21:14 2014 +0000 @@ -63,6 +63,10 @@ SA_CLASSPATH=$(shell test -f $(ALT_SA_CLASSPATH) && echo $(ALT_SA_CLASSPATH)) endif +ifneq ($(SA_CLASSPATH),) + SA_CLASSPATH_ARG := -classpath $(SA_CLASSPATH) +endif + # TODO: if it's a modules image, check if SA module is installed. MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules @@ -114,7 +118,7 @@ # are in AGENT_FILES, so use the shell to expand them. # Be extra carefull to not produce too long command lines in the shell! $(foreach file,$(AGENT_FILES),$(shell ls -1 $(file) >> $(AGENT_FILES_LIST))) - $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES_LIST) + $(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) $(SA_CLASSPATH_ARG) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES_LIST) $(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer $(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES) $(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/os/aix/vm/os_aix.cpp --- a/hotspot/src/os/aix/vm/os_aix.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/os/aix/vm/os_aix.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -512,15 +512,13 @@ #define DEFAULT_LIBPATH "/usr/lib:/lib" #define EXTENSIONS_DIR "/lib/ext" -#define ENDORSED_DIR "/lib/endorsed" // Buffer that fits several sprintfs. // Note that the space for the trailing null is provided // by the nulls included by the sizeof operator. const size_t bufsize = - MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. - (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR), // extensions dir - (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + MAX2((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR)); // extensions dir char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); // sysclasspath, java_home, dll_dir @@ -571,15 +569,10 @@ sprintf(buf, "%s" EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - // Endorsed standards default directory. - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf, mtInternal); #undef DEFAULT_LIBPATH #undef EXTENSIONS_DIR -#undef ENDORSED_DIR } //////////////////////////////////////////////////////////////////////////////// @@ -2778,6 +2771,10 @@ return ::read(fd, buf, nBytes); } +size_t os::read_at(int fd, void *buf, unsigned int nBytes, jlong offset) { + return ::pread(fd, buf, nBytes, offset); +} + void os::naked_short_sleep(jlong ms) { struct timespec req; diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/os/bsd/vm/os_bsd.cpp --- a/hotspot/src/os/bsd/vm/os_bsd.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -353,7 +353,6 @@ // Base path of extensions installed on the system. #define SYS_EXT_DIR "/usr/java/packages" #define EXTENSIONS_DIR "/lib/ext" -#define ENDORSED_DIR "/lib/endorsed" #ifndef __APPLE__ @@ -361,9 +360,8 @@ // Note that the space for the colon and the trailing null are provided // by the nulls included by the sizeof operator. const size_t bufsize = - MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. - (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir - (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + MAX2((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); // sysclasspath, java_home, dll_dir @@ -425,10 +423,6 @@ sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - // Endorsed standards default directory. - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf, mtInternal); #else // __APPLE__ @@ -445,9 +439,8 @@ // Note that the space for the colon and the trailing null are provided // by the nulls included by the sizeof operator. const size_t bufsize = - MAX3((size_t)MAXPATHLEN, // for dll_dir & friends. - (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + system_ext_size, // extensions dir - (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + MAX2((size_t)MAXPATHLEN, // for dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + system_ext_size); // extensions dir char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); // sysclasspath, java_home, dll_dir @@ -525,10 +518,6 @@ user_home_dir, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - // Endorsed standards default directory. - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf, mtInternal); #undef SYS_EXTENSIONS_DIR @@ -538,7 +527,6 @@ #undef SYS_EXT_DIR #undef EXTENSIONS_DIR -#undef ENDORSED_DIR } //////////////////////////////////////////////////////////////////////////////// @@ -2576,6 +2564,10 @@ RESTARTABLE_RETURN_INT(::read(fd, buf, nBytes)); } +size_t os::read_at(int fd, void *buf, unsigned int nBytes, jlong offset) { + RESTARTABLE_RETURN_INT(::pread(fd, buf, nBytes, offset)); +} + void os::naked_short_sleep(jlong ms) { struct timespec req; diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -337,15 +337,13 @@ // Base path of extensions installed on the system. #define SYS_EXT_DIR "/usr/java/packages" #define EXTENSIONS_DIR "/lib/ext" -#define ENDORSED_DIR "/lib/endorsed" // Buffer that fits several sprintfs. // Note that the space for the colon and the trailing null are provided // by the nulls included by the sizeof operator. const size_t bufsize = - MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. - (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir - (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + MAX2((size_t)MAXPATHLEN, // For dll_dir & friends. + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); // sysclasspath, java_home, dll_dir @@ -410,16 +408,11 @@ sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - // Endorsed standards default directory. - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf, mtInternal); #undef DEFAULT_LIBPATH #undef SYS_EXT_DIR #undef EXTENSIONS_DIR -#undef ENDORSED_DIR } //////////////////////////////////////////////////////////////////////////////// @@ -3783,6 +3776,10 @@ return ::read(fd, buf, nBytes); } +size_t os::read_at(int fd, void *buf, unsigned int nBytes, jlong offset) { + return ::pread(fd, buf, nBytes, offset); +} + // Short sleep, direct OS call. // // Note: certain versions of Linux CFS scheduler (since 2.6.23) do not guarantee diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -609,17 +609,15 @@ // Base path of extensions installed on the system. #define SYS_EXT_DIR "/usr/jdk/packages" #define EXTENSIONS_DIR "/lib/ext" -#define ENDORSED_DIR "/lib/endorsed" char cpu_arch[12]; // Buffer that fits several sprintfs. // Note that the space for the colon and the trailing null are provided // by the nulls included by the sizeof operator. const size_t bufsize = - MAX4((size_t)MAXPATHLEN, // For dll_dir & friends. + MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch), // invariant ld_library_path - (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir - (size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir + (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); // sysclasspath, java_home, dll_dir @@ -765,15 +763,10 @@ sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - // Endorsed standards default directory. - sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home()); - Arguments::set_endorsed_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf, mtInternal); #undef SYS_EXT_DIR #undef EXTENSIONS_DIR -#undef ENDORSED_DIR } void os::breakpoint() { @@ -3164,6 +3157,15 @@ return res; } +size_t os::read_at(int fd, void *buf, unsigned int nBytes, jlong offset) { + size_t res; + JavaThread* thread = (JavaThread*)Thread::current(); + assert(thread->thread_state() == _thread_in_vm, "Assumed _thread_in_vm"); + ThreadBlockInVM tbiv(thread); + RESTARTABLE(::pread(fd, buf, (size_t) nBytes, offset), res); + return res; +} + size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) { size_t res; assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -292,19 +292,6 @@ #undef BIN_DIR #undef PACKAGE_DIR - // Default endorsed standards directory. - { -#define ENDORSED_DIR "\\lib\\endorsed" - size_t len = strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR); - char * buf = NEW_C_HEAP_ARRAY(char, len, mtInternal); - sprintf(buf, "%s%s", Arguments::get_java_home(), ENDORSED_DIR); - Arguments::set_endorsed_dirs(buf); - // (Arguments::set_endorsed_dirs() calls SystemProperty::set_value(), which - // duplicates the input.) - FREE_C_HEAP_ARRAY(char, buf, mtInternal); -#undef ENDORSED_DIR - } - #ifndef _WIN64 // set our UnhandledExceptionFilter and save any previous one prev_uef_handler = SetUnhandledExceptionFilter(Handle_FLT_Exception); @@ -4376,6 +4363,23 @@ return (jlong) ::_lseeki64(fd, offset, whence); } +size_t os::read_at(int fd, void *buf, unsigned int nBytes, jlong offset) { + OVERLAPPED ov; + DWORD nread; + BOOL result; + + ZeroMemory(&ov, sizeof(ov)); + ov.Offset = (DWORD)offset; + ov.OffsetHigh = (DWORD)(offset >> 32); + + HANDLE h = (HANDLE)::_get_osfhandle(fd); + + result = ReadFile(h, (LPVOID)buf, nBytes, &nread, &ov); + + return result ? nread : 0; +} + + // This method is a slightly reworked copy of JDK's sysNativePath // from src/windows/hpi/src/path_md.c diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/classfile/classLoader.cpp --- a/hotspot/src/share/vm/classfile/classLoader.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -28,6 +28,7 @@ #include "classfile/classLoader.hpp" #include "classfile/classLoaderExt.hpp" #include "classfile/classLoaderData.inline.hpp" +#include "classfile/imageFile.hpp" #include "classfile/javaClasses.hpp" #if INCLUDE_CDS #include "classfile/sharedPathsMiscInfo.hpp" @@ -67,7 +68,7 @@ #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" -// Entry points in zip.dll for loading zip/jar file entries +// Entry points in zip.dll for loading zip/jar file entries and image file entries typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg); typedef void (JNICALL *ZipClose_t)(jzfile *zip); @@ -75,6 +76,7 @@ typedef jboolean (JNICALL *ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf); typedef jboolean (JNICALL *ReadMappedEntry_t)(jzfile *zip, jzentry *entry, unsigned char **buf, char *namebuf); typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n); +typedef jboolean (JNICALL *ZipInflateFully_t)(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg); typedef jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len); static ZipOpen_t ZipOpen = NULL; @@ -84,6 +86,7 @@ static ReadMappedEntry_t ReadMappedEntry = NULL; static GetNextEntry_t GetNextEntry = NULL; static canonicalize_fn_t CanonicalizeEntry = NULL; +static ZipInflateFully_t ZipInflateFully = NULL; static Crc32_t Crc32 = NULL; // Globals @@ -322,6 +325,8 @@ } bool LazyClassPathEntry::is_jar_file() { + size_t len = strlen(_path); + if (len < 4 || strcmp(_path + len - 4, ".jar") != 0) return false; return ((_st.st_mode & S_IFREG) == S_IFREG); } @@ -385,6 +390,78 @@ } } +ClassPathImageEntry::ClassPathImageEntry(char* name) : ClassPathEntry(), _image(new ImageFile(name)) { + bool opened = _image->open(); + if (!opened) { + _image = NULL; + } +} + +ClassPathImageEntry::~ClassPathImageEntry() { + if (_image) { + _image->close(); + _image = NULL; + } +} + +const char* ClassPathImageEntry::name() { + return _image ? _image->name() : ""; +} + +ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) { + u1* buffer; + u8 size; + _image->get_resource(name, buffer, size); + + if (buffer) { + if (UsePerfData) { + ClassLoader::perf_sys_classfile_bytes_read()->inc(size); + } + return new ClassFileStream(buffer, (int)size, (char*)name); // Resource allocated + } + + return NULL; +} + +#ifndef PRODUCT +void ClassPathImageEntry::compile_the_world(Handle loader, TRAPS) { + tty->print_cr("CompileTheWorld : Compiling all classes in %s", name()); + tty->cr(); + const ImageStrings strings = _image->get_strings(); + // Retrieve each path component string. + u4 count = _image->get_location_count(); + for (u4 i = 0; i < count; i++) { + u1* location_data = _image->get_location_data(i); + + if (location_data) { + ImageLocation location(location_data); + const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings); + const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings); + const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings); + assert((strlen(parent) + strlen(base) + strlen(extension)) < JVM_MAXPATHLEN, "path exceeds buffer"); + char path[JVM_MAXPATHLEN]; + strcpy(path, parent); + strcat(path, base); + strcat(path, extension); + ClassLoader::compile_the_world_in(path, loader, CHECK); + } + } + if (HAS_PENDING_EXCEPTION) { + if (PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())) { + CLEAR_PENDING_EXCEPTION; + tty->print_cr("\nCompileTheWorld : Ran out of memory\n"); + tty->print_cr("Increase class metadata storage if a limit was set"); + } else { + tty->print_cr("\nCompileTheWorld : Unexpected exception occurred\n"); + } + } +} + +bool ClassPathImageEntry::is_jrt() { + return string_ends_with(name(), "bootmodules.jimage"); +} +#endif + static void print_meta_index(LazyClassPathEntry* entry, GrowableArray& meta_packages) { tty->print("[Meta index for %s=", entry->name()); @@ -634,7 +711,7 @@ } ClassPathEntry* new_entry = NULL; if ((st->st_mode & S_IFREG) == S_IFREG) { - // Regular file, should be a zip file + // Regular file, should be a zip or image file // Canonicalized filename char canonical_path[JVM_MAXPATHLEN]; if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { @@ -645,6 +722,11 @@ return NULL; } } + // TODO - add proper criteria for selecting image file + ClassPathImageEntry* entry = new ClassPathImageEntry(canonical_path); + if (entry->is_open()) { + new_entry = entry; + } else { char* error_msg = NULL; jzfile* zip; { @@ -655,9 +737,6 @@ } if (zip != NULL && error_msg == NULL) { new_entry = new ClassPathZipEntry(zip, path); - if (TraceClassLoading || TraceClassPaths) { - tty->print_cr("[Opened %s]", path); - } } else { ResourceMark rm(thread); char *msg; @@ -675,10 +754,14 @@ return NULL; } } + } + if (TraceClassLoading || TraceClassPaths) { + tty->print_cr("[Opened %s]", path); + } } else { // Directory new_entry = new ClassPathDirEntry(path); - if (TraceClassLoading || TraceClassPaths) { + if (TraceClassLoading) { tty->print_cr("[Path %s]", path); } } @@ -801,6 +884,7 @@ ReadEntry = CAST_TO_FN_PTR(ReadEntry_t, os::dll_lookup(handle, "ZIP_ReadEntry")); ReadMappedEntry = CAST_TO_FN_PTR(ReadMappedEntry_t, os::dll_lookup(handle, "ZIP_ReadMappedEntry")); GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, os::dll_lookup(handle, "ZIP_GetNextEntry")); + ZipInflateFully = CAST_TO_FN_PTR(ZipInflateFully_t, os::dll_lookup(handle, "ZIP_InflateFully")); Crc32 = CAST_TO_FN_PTR(Crc32_t, os::dll_lookup(handle, "ZIP_CRC32")); // ZIP_Close is not exported on Windows in JDK5.0 so don't abort if ZIP_Close is NULL @@ -809,12 +893,20 @@ vm_exit_during_initialization("Corrupted ZIP library", path); } + if (ZipInflateFully == NULL) { + vm_exit_during_initialization("Corrupted ZIP library ZIP_InflateFully missing", path); + } + // Lookup canonicalize entry in libjava.dll void *javalib_handle = os::native_java_library(); CanonicalizeEntry = CAST_TO_FN_PTR(canonicalize_fn_t, os::dll_lookup(javalib_handle, "Canonicalize")); // This lookup only works on 1.3. Do not check for non-null here } +jboolean ClassLoader::decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg) { + return (*ZipInflateFully)(in, inSize, out, outSize, pmsg); +} + int ClassLoader::crc32(int crc, const char* buf, int len) { assert(Crc32 != NULL, "ZIP_CRC32 is not found"); return (*Crc32)(crc, (const jbyte*)buf, len); @@ -1367,8 +1459,7 @@ tty->cr(); } - -bool ClassPathDirEntry::is_rt_jar() { +bool ClassPathDirEntry::is_jrt() { return false; } @@ -1393,13 +1484,13 @@ } } -bool ClassPathZipEntry::is_rt_jar() { +bool ClassPathZipEntry::is_jrt() { real_jzfile* zip = (real_jzfile*) _zip; int len = (int)strlen(zip->name); // Check whether zip name ends in "rt.jar" // This will match other archives named rt.jar as well, but this is // only used for debugging. - return (len >= 6) && (strcasecmp(zip->name + len - 6, "rt.jar") == 0); + return string_ends_with(zip->name, "rt.jar"); } void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) { @@ -1409,7 +1500,7 @@ } } -bool LazyClassPathEntry::is_rt_jar() { +bool LazyClassPathEntry::is_jrt() { Thread* THREAD = Thread::current(); ClassPathEntry* cpe = resolve_entry(THREAD); return (cpe != NULL) ? cpe->is_jar_file() : false; @@ -1428,7 +1519,7 @@ jlong start = os::javaTimeMillis(); while (e != NULL) { // We stop at rt.jar, unless it is the first bootstrap path entry - if (e->is_rt_jar() && e != _first_entry) break; + if (e->is_jrt() && e != _first_entry) break; e->compile_the_world(system_class_loader, CATCH); e = e->next(); } @@ -1476,9 +1567,9 @@ } void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { - int len = (int)strlen(name); - if (len > 6 && strcmp(".class", name + len - 6) == 0) { + if (string_ends_with(name, ".class")) { // We have a .class file + int len = (int)strlen(name); char buffer[2048]; strncpy(buffer, name, len - 6); buffer[len-6] = 0; diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/classfile/classLoader.hpp --- a/hotspot/src/share/vm/classfile/classLoader.hpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/classfile/classLoader.hpp Wed Dec 03 14:21:14 2014 +0000 @@ -66,7 +66,7 @@ virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0; // Debugging NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;) - NOT_PRODUCT(virtual bool is_rt_jar() = 0;) + NOT_PRODUCT(virtual bool is_jrt() = 0;) }; @@ -80,7 +80,7 @@ ClassFileStream* open_stream(const char* name, TRAPS); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_rt_jar();) + NOT_PRODUCT(bool is_jrt();) }; @@ -112,7 +112,7 @@ void contents_do(void f(const char* name, void* context), void* context); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_rt_jar();) + NOT_PRODUCT(bool is_jrt();) }; @@ -138,7 +138,25 @@ virtual bool is_lazy(); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_rt_jar();) + NOT_PRODUCT(bool is_jrt();) +}; + +// For java image files +class ImageFile; +class ClassPathImageEntry: public ClassPathEntry { +private: + ImageFile *_image; +public: + bool is_jar_file() { return false; } + bool is_open() { return _image != NULL; } + const char* name(); + ClassPathImageEntry(char* name); + ~ClassPathImageEntry(); + ClassFileStream* open_stream(const char* name, TRAPS); + + // Debugging + NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) + NOT_PRODUCT(bool is_jrt();) }; class PackageHashtable; @@ -226,6 +244,7 @@ // to avoid confusing the zip library static bool get_canonical_path(const char* orig, char* out, int len); public: + static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg); static int crc32(int crc, const char* buf, int len); static bool update_class_path_entry_list(const char *path, bool check_for_duplicates, diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/classfile/imageFile.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/classfile/imageFile.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/imageFile.hpp" +#include "runtime/os.inline.hpp" +#include "utilities/bytes.hpp" + + +// Compute the Perfect Hashing hash code for the supplied string. +u4 ImageStrings::hash_code(const char* string, u4 seed) { + u1* bytes = (u1*)string; + + // Compute hash code. + for (u1 byte = *bytes++; byte; byte = *bytes++) { + seed = (seed * HASH_MULTIPLIER) ^ byte; + } + + // Ensure the result is unsigned. + return seed & 0x7FFFFFFF; +} + +// Test to see if string begins with start. If so returns remaining portion +// of string. Otherwise, NULL. +const char* ImageStrings::starts_with(const char* string, const char* start) { + char ch1, ch2; + + // Match up the strings the best we can. + while ((ch1 = *string) && (ch2 = *start)) { + if (ch1 != ch2) { + // Mismatch, return NULL. + return NULL; + } + + string++, start++; + } + + // Return remainder of string. + return string; +} + +ImageLocation::ImageLocation(u1* data) { + // Deflate the attribute stream into an array of attributes. + memset(_attributes, 0, sizeof(_attributes)); + u1 byte; + + while ((byte = *data) != ATTRIBUTE_END) { + u1 kind = attribute_kind(byte); + u1 n = attribute_length(byte); + assert(kind < ATTRIBUTE_COUNT, "invalid image location attribute"); + _attributes[kind] = attribute_value(data + 1, n); + data += n + 1; + } +} + +ImageFile::ImageFile(const char* name) { + // Copy the image file name. + _name = NEW_C_HEAP_ARRAY(char, strlen(name)+1, mtClass); + strcpy(_name, name); + + // Initialize for a closed file. + _fd = -1; + _memory_mapped = true; + _index_data = NULL; +} + +ImageFile::~ImageFile() { + // Ensure file is closed. + close(); + + // Free up name. + FREE_C_HEAP_ARRAY(char, _name, mtClass); +} + +bool ImageFile::open() { + // If file exists open for reading. + struct stat st; + if (os::stat(_name, &st) != 0 || + (st.st_mode & S_IFREG) != S_IFREG || + (_fd = os::open(_name, 0, O_RDONLY)) == -1) { + return false; + } + + // Read image file header and verify. + u8 header_size = sizeof(ImageHeader); + if (os::read(_fd, &_header, header_size) != header_size || + _header._magic != IMAGE_MAGIC || + _header._major_version != MAJOR_VERSION || + _header._minor_version != MINOR_VERSION) { + close(); + return false; + } + + // Memory map index. + _index_size = index_size(); + _index_data = (u1*)os::map_memory(_fd, _name, 0, NULL, _index_size, true, false); + + // Failing that, read index into C memory. + if (_index_data == NULL) { + _memory_mapped = false; + _index_data = NEW_RESOURCE_ARRAY(u1, _index_size); + + if (os::seek_to_file_offset(_fd, 0) == -1) { + close(); + return false; + } + + if (os::read(_fd, _index_data, _index_size) != _index_size) { + close(); + return false; + } + + return true; + } + +// Used to advance a pointer, unstructured. +#undef nextPtr +#define nextPtr(base, fromType, count, toType) (toType*)((fromType*)(base) + (count)) + // Pull tables out from the index. + _redirect_table = nextPtr(_index_data, u1, header_size, s4); + _offsets_table = nextPtr(_redirect_table, s4, _header._location_count, u4); + _location_bytes = nextPtr(_offsets_table, u4, _header._location_count, u1); + _string_bytes = nextPtr(_location_bytes, u1, _header._locations_size, u1); +#undef nextPtr + + // Successful open. + return true; +} + +void ImageFile::close() { + // Dealllocate the index. + if (_index_data) { + if (_memory_mapped) { + os::unmap_memory((char*)_index_data, _index_size); + } else { + FREE_RESOURCE_ARRAY(u1, _index_data, _index_size); + } + + _index_data = NULL; + } + + // close file. + if (_fd != -1) { + os::close(_fd); + _fd = -1; + } + +} + +// Return the attribute stream for a named resourced. +u1* ImageFile::find_location_data(const char* path) const { + // Compute hash. + u4 hash = ImageStrings::hash_code(path) % _header._location_count; + s4 redirect = _redirect_table[hash]; + + if (!redirect) { + return NULL; + } + + u4 index; + + if (redirect < 0) { + // If no collision. + index = -redirect - 1; + } else { + // If collision, recompute hash code. + index = ImageStrings::hash_code(path, redirect) % _header._location_count; + } + + assert(index < _header._location_count, "index exceeds location count"); + u4 offset = _offsets_table[index]; + assert(offset < _header._locations_size, "offset exceeds location attributes size"); + + if (offset == 0) { + return NULL; + } + + return _location_bytes + offset; +} + +// Verify that a found location matches the supplied path. +bool ImageFile::verify_location(ImageLocation& location, const char* path) const { + // Retrieve each path component string. + ImageStrings strings(_string_bytes, _header._strings_size); + // Match a path with each subcomponent without concatenation (copy). + // Match up path parent. + const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings); + const char* next = ImageStrings::starts_with(path, parent); + // Continue only if a complete match. + if (!next) return false; + // Match up path base. + const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings); + next = ImageStrings::starts_with(next, base); + // Continue only if a complete match. + if (!next) return false; + // Match up path extension. + const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings); + next = ImageStrings::starts_with(next, extension); + + // True only if complete match and no more characters. + return next && *next == '\0'; +} + +// Return the resource for the supplied location. +u1* ImageFile::get_resource(ImageLocation& location) const { + // Retrieve the byte offset and size of the resource. + u8 offset = _index_size + location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET); + u8 size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED); + u8 compressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_COMPRESSED); + u8 read_size = compressed_size ? compressed_size : size; + + // Allocate space for the resource. + u1* data = NEW_RESOURCE_ARRAY(u1, read_size); + + bool is_read = os::read_at(_fd, data, read_size, offset) == read_size; + guarantee(is_read, "error reading from image or short read"); + + // If not compressed, just return the data. + if (!compressed_size) { + return data; + } + + u1* uncompressed = NEW_RESOURCE_ARRAY(u1, size); + char* msg = NULL; + jboolean res = ClassLoader::decompress(data, compressed_size, uncompressed, size, &msg); + if (!res) warning("decompression failed due to %s\n", msg); + guarantee(res, "decompression failed"); + + return uncompressed; +} + +void ImageFile::get_resource(const char* path, u1*& buffer, u8& size) const { + buffer = NULL; + size = 0; + u1* data = find_location_data(path); + if (data) { + ImageLocation location(data); + if (verify_location(location, path)) { + size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED); + buffer = get_resource(location); + } + } +} + +GrowableArray* ImageFile::packages(const char* name) { + char entry[JVM_MAXPATHLEN]; + bool overflow = jio_snprintf(entry, sizeof(entry), "%s/packages.offsets", name) == -1; + guarantee(!overflow, "package name overflow"); + + u1* buffer; + u8 size; + + get_resource(entry, buffer, size); + guarantee(buffer, "missing module packages reource"); + ImageStrings strings(_string_bytes, _header._strings_size); + GrowableArray* pkgs = new GrowableArray(); + int count = size / 4; + for (int i = 0; i < count; i++) { + u4 offset = Bytes::get_Java_u4(buffer + (i*4)); + const char* p = strings.get(offset); + pkgs->append(p); + } + + return pkgs; +} diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/classfile/imageFile.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/classfile/imageFile.hpp Wed Dec 03 14:21:14 2014 +0000 @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_IMAGEFILE_HPP +#define SHARE_VM_CLASSFILE_IMAGEFILE_HPP + +#include "classfile/classLoader.hpp" +#include "memory/allocation.hpp" +#include "memory/allocation.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +// Image files are an alternate file format for storing classes and resources. The +// goal is to supply file access which is faster and smaller that the jar format. +// It should be noted that unlike jars information stored in an image is in native +// endian format. This allows the image to be memory mapped into memory without +// endian translation. This also means that images are platform dependent. +// +// Image files are structured as three sections; +// +// +-----------+ +// | Header | +// +-----------+ +// | | +// | Directory | +// | | +// +-----------+ +// | | +// | | +// | Resources | +// | | +// | | +// +-----------+ +// +// The header contains information related to identification and description of +// contents. +// +// +-------------------------+ +// | Magic (0xCAFEDADA) | +// +------------+------------+ +// | Major Vers | Minor Vers | +// +------------+------------+ +// | Location Count | +// +-------------------------+ +// | Attributes Size | +// +-------------------------+ +// | Strings Size | +// +-------------------------+ +// +// Magic - means of identifying validity of the file. This avoids requiring a +// special file extension. +// Major vers, minor vers - differences in version numbers indicate structural +// changes in the image. +// Location count - number of locations/resources in the file. This count is also +// the length of lookup tables used in the directory. +// Attributes size - number of bytes in the region used to store location attribute +// streams. +// Strings size - the size of the region used to store strings used by the +// directory and meta data. +// +// The directory contains information related to resource lookup. The algorithm +// used for lookup is "A Practical Minimal Perfect Hashing Method" +// (http://homepages.dcc.ufmg.br/~nivio/papers/wea05.pdf). Given a path string +// in the form /. return the resource location +// information; +// +// redirectIndex = hash(path, DEFAULT_SEED) % count; +// redirect = redirectTable[redirectIndex]; +// if (redirect == 0) return not found; +// locationIndex = redirect < 0 ? -1 - redirect : hash(path, redirect) % count; +// location = locationTable[locationIndex]; +// if (!verify(location, path)) return not found; +// return location; +// +// Note: The hash function takes an initial seed value. A different seed value +// usually returns a different result for strings that would otherwise collide with +// other seeds. The verify function guarantees the found resource location is +// indeed the resource we are looking for. +// +// The following is the format of the directory; +// +// +-------------------+ +// | Redirect Table | +// +-------------------+ +// | Attribute Offsets | +// +-------------------+ +// | Attribute Data | +// +-------------------+ +// | Strings | +// +-------------------+ +// +// Redirect Table - Array of 32-bit signed values representing actions that +// should take place for hashed strings that map to that +// value. Negative values indicate no hash collision and can be +// quickly converted to indices into attribute offsets. Positive +// values represent a new seed for hashing an index into attribute +// offsets. Zero indicates not found. +// Attribute Offsets - Array of 32-bit unsigned values representing offsets into +// attribute data. Attribute offsets can be iterated to do a +// full survey of resources in the image. +// Attribute Data - Bytes representing compact attribute data for locations. (See +// comments in ImageLocation.) +// Strings - Collection of zero terminated UTF-8 strings used by the directory and +// image meta data. Each string is accessed by offset. Each string is +// unique. Offset zero is reserved for the empty string. +// +// Note that the memory mapped directory assumes 32 bit alignment of the image +// header, the redirect table and the attribute offsets. +// + + +// Manage image file string table. +class ImageStrings { +private: + // Data bytes for strings. + u1* _data; + // Number of bytes in the string table. + u4 _size; + +public: + // Prime used to generate hash for Perfect Hashing. + static const u4 HASH_MULTIPLIER = 0x01000193; + + ImageStrings(u1* data, u4 size) : _data(data), _size(size) {} + + // Return the UTF-8 string beginning at offset. + inline const char* get(u4 offset) const { + assert(offset < _size, "offset exceeds string table size"); + return (const char*)(_data + offset); + } + + // Compute the Perfect Hashing hash code for the supplied string. + inline static u4 hash_code(const char* string) { + return hash_code(string, HASH_MULTIPLIER); + } + + // Compute the Perfect Hashing hash code for the supplied string, starting at seed. + static u4 hash_code(const char* string, u4 seed); + + // Test to see if string begins with start. If so returns remaining portion + // of string. Otherwise, NULL. Used to test sections of a path without + // copying. + static const char* starts_with(const char* string, const char* start); + +}; + +// Manage image file location attribute streams. Within an image, a location's +// attributes are compressed into a stream of bytes. An attribute stream is +// composed of individual attribute sequences. Each attribute sequence begins with +// a header byte containing the attribute 'kind' (upper 5 bits of header) and the +// 'length' less 1 (lower 3 bits of header) of bytes that follow containing the +// attribute value. Attribute values present as most significant byte first. +// +// Ex. Container offset (ATTRIBUTE_OFFSET) 0x33562 would be represented as 0x22 +// (kind = 4, length = 3), 0x03, 0x35, 0x62. +// +// An attribute stream is terminated with a header kind of ATTRIBUTE_END (header +// byte of zero.) +// +// ImageLocation inflates the stream into individual values stored in the long +// array _attributes. This allows an attribute value can be quickly accessed by +// direct indexing. Unspecified values default to zero. +// +// Notes: +// - Even though ATTRIBUTE_END is used to mark the end of the attribute stream, +// streams will contain zero byte values to represent lesser significant bits. +// Thus, detecting a zero byte is not sufficient to detect the end of an attribute +// stream. +// - ATTRIBUTE_OFFSET represents the number of bytes from the beginning of the region +// storing the resources. Thus, in an image this represents the number of bytes +// after the directory. +// - Currently, compressed resources are represented by having a non-zero +// ATTRIBUTE_COMPRESSED value. This represents the number of bytes stored in the +// image, and the value of ATTRIBUTE_UNCOMPRESSED represents number of bytes of the +// inflated resource in memory. If the ATTRIBUTE_COMPRESSED is zero then the value +// of ATTRIBUTE_UNCOMPRESSED represents both the number of bytes in the image and +// in memory. In the future, additional compression techniques will be used and +// represented differently. +// - Package strings include trailing slash and extensions include prefix period. +// +class ImageLocation { +public: + // Attribute kind enumeration. + static const u1 ATTRIBUTE_END = 0; // End of attribute stream marker + static const u1 ATTRIBUTE_BASE = 1; // String table offset of resource path base + static const u1 ATTRIBUTE_PARENT = 2; // String table offset of resource path parent + static const u1 ATTRIBUTE_EXTENSION = 3; // String table offset of resource path extension + static const u1 ATTRIBUTE_OFFSET = 4; // Container byte offset of resource + static const u1 ATTRIBUTE_COMPRESSED = 5; // In image byte size of the compressed resource + static const u1 ATTRIBUTE_UNCOMPRESSED = 6; // In memory byte size of the uncompressed resource + static const u1 ATTRIBUTE_COUNT = 7; // Number of attribute kinds + +private: + // Values of inflated attributes. + u8 _attributes[ATTRIBUTE_COUNT]; + + // Return the attribute value number of bytes. + inline static u1 attribute_length(u1 data) { + return (data & 0x7) + 1; + } + + // Return the attribute kind. + inline static u1 attribute_kind(u1 data) { + u1 kind = data >> 3; + assert(kind < ATTRIBUTE_COUNT, "invalid attribute kind"); + return kind; + } + + // Return the attribute length. + inline static u8 attribute_value(u1* data, u1 n) { + assert(0 < n && n <= 8, "invalid attribute value length"); + u8 value = 0; + + // Most significant bytes first. + for (u1 i = 0; i < n; i++) { + value <<= 8; + value |= data[i]; + } + + return value; + } + +public: + ImageLocation(u1* data); + + // Retrieve an attribute value from the inflated array. + inline u8 get_attribute(u1 kind) const { + assert(ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT, "invalid attribute kind"); + return _attributes[kind]; + } + + // Retrieve an attribute string value from the inflated array. + inline const char* get_attribute(u4 kind, const ImageStrings& strings) const { + return strings.get((u4)get_attribute(kind)); + } +}; + +// Manage the image file. +class ImageFile: public CHeapObj { +private: + // Image file marker. + static const u4 IMAGE_MAGIC = 0xCAFEDADA; + // Image file major version number. + static const u2 MAJOR_VERSION = 0; + // Image file minor version number. + static const u2 MINOR_VERSION = 1; + + struct ImageHeader { + u4 _magic; // Image file marker + u2 _major_version; // Image file major version number + u2 _minor_version; // Image file minor version number + u4 _location_count; // Number of locations managed in index. + u4 _locations_size; // Number of bytes in attribute table. + u4 _strings_size; // Number of bytes in string table. + }; + + char* _name; // Name of image + int _fd; // File descriptor + bool _memory_mapped; // Is file memory mapped + ImageHeader _header; // Image header + u8 _index_size; // Total size of index + u1* _index_data; // Raw index data + s4* _redirect_table; // Perfect hash redirect table + u4* _offsets_table; // Location offset table + u1* _location_bytes; // Location attributes + u1* _string_bytes; // String table + + // Compute number of bytes in image file index. + inline u8 index_size() { + return sizeof(ImageHeader) + + _header._location_count * sizeof(u4) * 2 + + _header._locations_size + + _header._strings_size; + } + +public: + ImageFile(const char* name); + ~ImageFile(); + + // Open image file for access. + bool open(); + // Close image file. + void close(); + + // Retrieve name of image file. + inline const char* name() const { + return _name; + } + + // Return a string table accessor. + inline const ImageStrings get_strings() const { + return ImageStrings(_string_bytes, _header._strings_size); + } + + // Return number of locations in image file index. + inline u4 get_location_count() const { + return _header._location_count; + } + + // Return location attribute stream for location i. + inline u1* get_location_data(u4 i) const { + u4 offset = _offsets_table[i]; + + return offset != 0 ? _location_bytes + offset : NULL; + } + + // Return the attribute stream for a named resourced. + u1* find_location_data(const char* path) const; + + // Verify that a found location matches the supplied path. + bool verify_location(ImageLocation& location, const char* path) const; + + // Return the resource for the supplied location info. + u1* get_resource(ImageLocation& location) const; + + // Return the resource associated with the path else NULL if not found. + void get_resource(const char* path, u1*& buffer, u8& size) const; + + // Return an array of packages for a given module + GrowableArray* packages(const char* name); +}; + +#endif // SHARE_VM_CLASSFILE_IMAGEFILE_HPP diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -110,7 +110,7 @@ bool SharedPathsMiscInfo::check(jint type, const char* path) { switch (type) { case BOOT: - if (strcmp(path, Arguments::get_sysclasspath()) != 0) { + if (os::file_name_strcmp(path, Arguments::get_sysclasspath()) != 0) { return fail("[BOOT classpath mismatch, actual: -Dsun.boot.class.path=", Arguments::get_sysclasspath()); } break; diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/memory/filemap.cpp --- a/hotspot/src/share/vm/memory/filemap.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/memory/filemap.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -217,9 +217,14 @@ EXCEPTION_MARK; // The following call should never throw, but would exit VM on error. SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); } else { - ent->_filesize = -1; - if (!os::dir_is_empty(name)) { - ClassLoader::exit_with_path_failure("Cannot have non-empty directory in archived classpaths", name); + struct stat st; + if ((os::stat(name, &st) == 0) && ((st.st_mode & S_IFDIR) == S_IFDIR)) { + if (!os::dir_is_empty(name)) { + ClassLoader::exit_with_path_failure("Cannot have non-empty directory in archived classpaths", name); + } + ent->_filesize = -1; + } else { + ent->_filesize = -2; } } ent->_name = strptr; @@ -271,7 +276,7 @@ fail_continue("directory is not empty: %s", name); ok = false; } - } else { + } else if (ent->is_jar()) { if (ent->_timestamp != st.st_mtime || ent->_filesize != st.st_size) { ok = false; diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/memory/filemap.hpp --- a/hotspot/src/share/vm/memory/filemap.hpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/memory/filemap.hpp Wed Dec 03 14:21:14 2014 +0000 @@ -44,8 +44,11 @@ class SharedClassPathEntry VALUE_OBJ_CLASS_SPEC { public: const char *_name; - time_t _timestamp; // jar timestamp, 0 if is directory - long _filesize; // jar file size, -1 if is directory + time_t _timestamp; // jar timestamp, 0 if is directory or other + long _filesize; // jar file size, -1 if is directory, -2 if other + bool is_jar() { + return _timestamp != 0; + } bool is_dir() { return _filesize == -1; } diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -115,8 +115,6 @@ vfprintf_hook_t Arguments::_vfprintf_hook = NULL; -SystemProperty *Arguments::_java_ext_dirs = NULL; -SystemProperty *Arguments::_java_endorsed_dirs = NULL; SystemProperty *Arguments::_sun_boot_library_path = NULL; SystemProperty *Arguments::_java_library_path = NULL; SystemProperty *Arguments::_java_home = NULL; @@ -125,6 +123,7 @@ char* Arguments::_meta_index_path = NULL; char* Arguments::_meta_index_dir = NULL; +char* Arguments::_ext_dirs = NULL; // Check if head of 'option' matches 'name', and sets 'tail' remaining part of option string @@ -184,8 +183,6 @@ // Following are JVMTI agent writable properties. // Properties values are set to NULL and they are // os specific they are initialized in os::init_system_properties_values(). - _java_ext_dirs = new SystemProperty("java.ext.dirs", NULL, true); - _java_endorsed_dirs = new SystemProperty("java.endorsed.dirs", NULL, true); _sun_boot_library_path = new SystemProperty("sun.boot.library.path", NULL, true); _java_library_path = new SystemProperty("java.library.path", NULL, true); _java_home = new SystemProperty("java.home", NULL, true); @@ -194,8 +191,6 @@ _java_class_path = new SystemProperty("java.class.path", "", true); // Add to System Property list. - PropertyList_add(&_system_properties, _java_ext_dirs); - PropertyList_add(&_system_properties, _java_endorsed_dirs); PropertyList_add(&_system_properties, _sun_boot_library_path); PropertyList_add(&_system_properties, _java_library_path); PropertyList_add(&_system_properties, _java_home); @@ -344,13 +339,9 @@ // components, in order: // // prefix // from -Xbootclasspath/p:... -// endorsed // the expansion of -Djava.endorsed.dirs=... // base // from os::get_system_properties() or -Xbootclasspath= // suffix // from -Xbootclasspath/a:... // -// java.endorsed.dirs is a list of directories; any jar or zip files in the -// directories are added to the sysclasspath just before the base. -// // This could be AllStatic, but it isn't needed after argument processing is // complete. class SysClassPath: public StackObj { @@ -364,16 +355,9 @@ inline void add_suffix(const char* suffix); inline void reset_path(const char* base); - // Expand the jar/zip files in each directory listed by the java.endorsed.dirs - // property. Must be called after all command-line arguments have been - // processed (in particular, -Djava.endorsed.dirs=...) and before calling - // combined_path(). - void expand_endorsed(); - inline const char* get_base() const { return _items[_scp_base]; } inline const char* get_prefix() const { return _items[_scp_prefix]; } inline const char* get_suffix() const { return _items[_scp_suffix]; } - inline const char* get_endorsed() const { return _items[_scp_endorsed]; } // Combine all the components into a single c-heap-allocated string; caller // must free the string if/when no longer needed. @@ -390,20 +374,17 @@ // base are allocated in the C heap and freed by this class. enum { _scp_prefix, // from -Xbootclasspath/p:... - _scp_endorsed, // the expansion of -Djava.endorsed.dirs=... _scp_base, // the default sysclasspath _scp_suffix, // from -Xbootclasspath/a:... _scp_nitems // the number of items, must be last. }; const char* _items[_scp_nitems]; - DEBUG_ONLY(bool _expansion_done;) }; SysClassPath::SysClassPath(const char* base) { memset(_items, 0, sizeof(_items)); _items[_scp_base] = base; - DEBUG_ONLY(_expansion_done = false;) } SysClassPath::~SysClassPath() { @@ -411,7 +392,6 @@ for (int i = 0; i < _scp_nitems; ++i) { if (i != _scp_base) reset_item_at(i); } - DEBUG_ONLY(_expansion_done = false;) } inline void SysClassPath::set_base(const char* base) { @@ -447,41 +427,11 @@ //------------------------------------------------------------------------------ -void SysClassPath::expand_endorsed() { - assert(_items[_scp_endorsed] == NULL, "can only be called once."); - - const char* path = Arguments::get_property("java.endorsed.dirs"); - if (path == NULL) { - path = Arguments::get_endorsed_dir(); - assert(path != NULL, "no default for java.endorsed.dirs"); - } - - char* expanded_path = NULL; - const char separator = *os::path_separator(); - const char* const end = path + strlen(path); - while (path < end) { - const char* tmp_end = strchr(path, separator); - if (tmp_end == NULL) { - expanded_path = add_jars_to_path(expanded_path, path); - path = end; - } else { - char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtInternal); - memcpy(dirpath, path, tmp_end - path); - dirpath[tmp_end - path] = '\0'; - expanded_path = add_jars_to_path(expanded_path, dirpath); - FREE_C_HEAP_ARRAY(char, dirpath, mtInternal); - path = tmp_end + 1; - } - } - _items[_scp_endorsed] = expanded_path; - DEBUG_ONLY(_expansion_done = true;) -} // Combine the bootclasspath elements, some of which may be null, into a single // c-heap-allocated string. char* SysClassPath::combined_path() { assert(_items[_scp_base] != NULL, "empty default sysclasspath"); - assert(_expansion_done, "must call expand_endorsed() first."); size_t lengths[_scp_nitems]; size_t total_len = 0; @@ -3084,6 +3034,20 @@ #endif // -D } else if (match_option(option, "-D", &tail)) { + if (match_option(option, "-Djava.endorsed.dirs=", &tail)) { + // abort if -Djava.endorsed.dirs is set + jio_fprintf(defaultStream::output_stream(), + "-Djava.endorsed.dirs is not supported. Endorsed standards and standalone APIs\n" + "in modular form will be supported via the concept of upgradeable modules.\n"); + return JNI_EINVAL; + } + if (match_option(option, "-Djava.ext.dirs=", &tail)) { + // abort if -Djava.ext.dirs is set + jio_fprintf(defaultStream::output_stream(), + "-Djava.ext.dirs is not supported. Use -classpath instead.\n"); + return JNI_EINVAL; + } + if (!add_property(tail)) { return JNI_ENOMEM; } @@ -3529,11 +3493,89 @@ } } +static bool has_jar_files(const char* directory) { + DIR* dir = os::opendir(directory); + if (dir == NULL) return false; + + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal); + bool hasJarFile = false; + while (!hasJarFile && (entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + hasJarFile = ext > name && (os::file_name_strcmp(ext, ".jar") == 0); + } + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); + os::closedir(dir); + return hasJarFile ; +} + +static int check_non_empty_dirs(const char* path) { + const char separator = *os::path_separator(); + const char* const end = path + strlen(path); + int nonEmptyDirs = 0; + while (path < end) { + const char* tmp_end = strchr(path, separator); + if (tmp_end == NULL) { + if (has_jar_files(path)) { + nonEmptyDirs++; + jio_fprintf(defaultStream::output_stream(), + "Non-empty directory: %s\n", path); + } + path = end; + } else { + char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtInternal); + memcpy(dirpath, path, tmp_end - path); + dirpath[tmp_end - path] = '\0'; + if (has_jar_files(dirpath)) { + nonEmptyDirs++; + jio_fprintf(defaultStream::output_stream(), + "Non-empty directory: %s\n", dirpath); + } + FREE_C_HEAP_ARRAY(char, dirpath, mtInternal); + path = tmp_end + 1; + } + } + return nonEmptyDirs; +} + jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required) { - // This must be done after all -D arguments have been processed. - scp_p->expand_endorsed(); - - if (scp_assembly_required || scp_p->get_endorsed() != NULL) { + // check if the default lib/endorsed directory exists; if so, error + char path[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + sprintf(path, "%s%slib%sendorsed", Arguments::get_java_home(), fileSep, fileSep); + + if (CheckEndorsedAndExtDirs) { + int nonEmptyDirs = 0; + // check endorsed directory + nonEmptyDirs += check_non_empty_dirs(path); + // check the extension directories + nonEmptyDirs += check_non_empty_dirs(Arguments::get_ext_dirs()); + if (nonEmptyDirs > 0) { + return JNI_ERR; + } + } + + DIR* dir = os::opendir(path); + if (dir != NULL) { + jio_fprintf(defaultStream::output_stream(), + "/lib/endorsed is not supported. Endorsed standards and standalone APIs\n" + "in modular form will be supported via the concept of upgradeable modules.\n"); + os::closedir(dir); + return JNI_ERR; + } + + sprintf(path, "%s%slib%sext", Arguments::get_java_home(), fileSep, fileSep); + dir = os::opendir(path); + if (dir != NULL) { + jio_fprintf(defaultStream::output_stream(), + "/lib/ext exists, extensions mechanism no longer supported; " + "Use -classpath instead.\n."); + os::closedir(dir); + return JNI_ERR; + } + + if (scp_assembly_required) { // Assemble the bootclasspath elements into the final path. Arguments::set_sysclasspath(scp_p->combined_path()); } diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/runtime/arguments.hpp --- a/hotspot/src/share/vm/runtime/arguments.hpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Dec 03 14:21:14 2014 +0000 @@ -254,8 +254,6 @@ static SystemProperty* _system_properties; // Quick accessor to System properties in the list: - static SystemProperty *_java_ext_dirs; - static SystemProperty *_java_endorsed_dirs; static SystemProperty *_sun_boot_library_path; static SystemProperty *_java_library_path; static SystemProperty *_java_home; @@ -266,6 +264,10 @@ static char* _meta_index_path; static char* _meta_index_dir; + // temporary: to emit warning if the default ext dirs are not empty. + // remove this variable when the warning is no longer needed. + static char* _ext_dirs; + // java.vendor.url.bug, bug reporting URL for fatal errors. static const char* _java_vendor_url_bug; @@ -586,8 +588,7 @@ static void set_dll_dir(char *value) { _sun_boot_library_path->set_value(value); } static void set_java_home(char *value) { _java_home->set_value(value); } static void set_library_path(char *value) { _java_library_path->set_value(value); } - static void set_ext_dirs(char *value) { _java_ext_dirs->set_value(value); } - static void set_endorsed_dirs(char *value) { _java_endorsed_dirs->set_value(value); } + static void set_ext_dirs(char *value) { _ext_dirs = os::strdup_check_oom(value); } static void set_sysclasspath(char *value) { _sun_boot_class_path->set_value(value); } static void append_sysclasspath(const char *value) { _sun_boot_class_path->append_value(value); } static void set_meta_index_path(char* meta_index_path, char* meta_index_dir) { @@ -597,14 +598,14 @@ static char* get_java_home() { return _java_home->value(); } static char* get_dll_dir() { return _sun_boot_library_path->value(); } - static char* get_endorsed_dir() { return _java_endorsed_dirs->value(); } static char* get_sysclasspath() { return _sun_boot_class_path->value(); } static char* get_meta_index_path() { return _meta_index_path; } static char* get_meta_index_dir() { return _meta_index_dir; } - static char* get_ext_dirs() { return _java_ext_dirs->value(); } + static char* get_ext_dirs() { return _ext_dirs; } static char* get_appclasspath() { return _java_class_path->value(); } static void fix_appclasspath(); + // Operation modi static Mode mode() { return _mode; } static bool is_interpreter_only() { return mode() == _int; } diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Dec 03 14:21:14 2014 +0000 @@ -1233,6 +1233,9 @@ product(bool, CheckJNICalls, false, \ "Verify all arguments to JNI calls") \ \ + product(bool, CheckEndorsedAndExtDirs, false, \ + "Verify the endorsed and extension directories are not used") \ + \ product(bool, UseFastJNIAccessors, true, \ "Use optimized versions of GetField") \ \ diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -1230,11 +1230,21 @@ Arguments::set_meta_index_path(meta_index, meta_index_dir); char* sysclasspath = NULL; + struct stat st; + + // modular image if bootmodules.jimage exists + char* jimage = format_boot_path("%/lib/modules/bootmodules.jimage", home, home_len, fileSep, pathSep); + if (jimage == NULL) return false; + bool has_jimage = (os::stat(jimage, &st) == 0); + if (has_jimage) { + Arguments::set_sysclasspath(jimage); + return true; + } + FREE_C_HEAP_ARRAY(char, jimage, mtInternal); // images build if rt.jar exists char* rt_jar = format_boot_path("%/lib/rt.jar", home, home_len, fileSep, pathSep); if (rt_jar == NULL) return false; - struct stat st; bool has_rt_jar = (os::stat(rt_jar, &st) == 0); FREE_C_HEAP_ARRAY(char, rt_jar, mtInternal); diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Dec 03 14:21:14 2014 +0000 @@ -500,6 +500,7 @@ //File i/o operations static size_t read(int fd, void *buf, unsigned int nBytes); + static size_t read_at(int fd, void *buf, unsigned int nBytes, jlong offset); static size_t restartable_read(int fd, void *buf, unsigned int nBytes); static size_t write(int fd, const void *buf, unsigned int nBytes); diff -r 7ead528de130 -r 47f369e3c69c hotspot/src/share/vm/runtime/statSampler.cpp --- a/hotspot/src/share/vm/runtime/statSampler.cpp Tue Nov 18 15:25:14 2014 -0800 +++ b/hotspot/src/share/vm/runtime/statSampler.cpp Wed Dec 03 14:21:14 2014 +0000 @@ -225,8 +225,6 @@ "java.vm.info", "java.library.path", "java.class.path", - "java.endorsed.dirs", - "java.ext.dirs", "java.version", "java.home", NULL