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
--- 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
--- 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;
--- 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;
--- 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
--- 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,
--- 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
--- 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<char*>& 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;
--- 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,
--- /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<const char*>* 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<const char*>* pkgs = new GrowableArray<const char*>();
+ 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;
+}
--- /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 <package>/<base>.<extension> 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<mtClass> {
+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<const char*>* packages(const char* name);
+};
+
+#endif // SHARE_VM_CLASSFILE_IMAGEFILE_HPP
--- 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;
--- 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;
--- 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;
}
--- 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(),
+ "<JAVA_HOME>/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(),
+ "<JAVA_HOME>/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());
}
--- 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; }
--- 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 Get<Primitive>Field") \
\
--- 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);
--- 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);
--- 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