src/share/vm/classfile/classLoader.cpp
Print this page
*** 26,35 ****
--- 26,36 ----
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#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"
#include "classfile/sharedClassUtil.hpp"
#endif
*** 65,91 ****
#include "services/threadService.hpp"
#include "utilities/events.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/hashtable.inline.hpp"
! // Entry points in zip.dll for loading zip/jar file entries
typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg);
typedef void (JNICALL *ZipClose_t)(jzfile *zip);
typedef jzentry* (JNICALL *FindEntry_t)(jzfile *zip, const char *name, jint *sizeP, jint *nameLen);
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 jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len);
static ZipOpen_t ZipOpen = NULL;
static ZipClose_t ZipClose = NULL;
static FindEntry_t FindEntry = NULL;
static ReadEntry_t ReadEntry = NULL;
static ReadMappedEntry_t ReadMappedEntry = NULL;
static GetNextEntry_t GetNextEntry = NULL;
static canonicalize_fn_t CanonicalizeEntry = NULL;
static Crc32_t Crc32 = NULL;
// Globals
PerfCounter* ClassLoader::_perf_accumulated_time = NULL;
--- 66,94 ----
#include "services/threadService.hpp"
#include "utilities/events.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/hashtable.inline.hpp"
! // 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);
typedef jzentry* (JNICALL *FindEntry_t)(jzfile *zip, const char *name, jint *sizeP, jint *nameLen);
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;
static ZipClose_t ZipClose = NULL;
static FindEntry_t FindEntry = NULL;
static ReadEntry_t ReadEntry = NULL;
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
PerfCounter* ClassLoader::_perf_accumulated_time = NULL;
*** 320,329 ****
--- 323,334 ----
LazyClassPathEntry::~LazyClassPathEntry() {
os::free((void*)_path);
}
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);
}
ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) {
if (_resolved_entry != NULL) {
*** 383,392 ****
--- 388,469 ----
*filesize = 0;
return NULL;
}
}
+ 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());
for (int i = 0; i < meta_packages.length(); i++) {
if (i > 0) tty->print(" ");
*** 632,665 ****
if (lazy) {
return new LazyClassPathEntry(path, st, throw_exception);
}
ClassPathEntry* new_entry = NULL;
if ((st->st_mode & S_IFREG) == S_IFREG) {
! // Regular file, should be a zip file
// Canonicalized filename
char canonical_path[JVM_MAXPATHLEN];
if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
// This matches the classic VM
if (throw_exception) {
THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL);
} else {
return NULL;
}
}
char* error_msg = NULL;
jzfile* zip;
{
// enable call to C land
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
zip = (*ZipOpen)(canonical_path, &error_msg);
}
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;
if (error_msg == NULL) {
msg = NEW_RESOURCE_ARRAY(char, strlen(path) + 128); ;
--- 709,744 ----
if (lazy) {
return new LazyClassPathEntry(path, st, throw_exception);
}
ClassPathEntry* new_entry = NULL;
if ((st->st_mode & S_IFREG) == S_IFREG) {
! // 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)) {
// This matches the classic VM
if (throw_exception) {
THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL);
} else {
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;
{
// enable call to C land
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
zip = (*ZipOpen)(canonical_path, &error_msg);
}
if (zip != NULL && error_msg == NULL) {
new_entry = new ClassPathZipEntry(zip, path);
} else {
ResourceMark rm(thread);
char *msg;
if (error_msg == NULL) {
msg = NEW_RESOURCE_ARRAY(char, strlen(path) + 128); ;
*** 673,686 ****
THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL);
} else {
return NULL;
}
}
} else {
// Directory
new_entry = new ClassPathDirEntry(path);
! if (TraceClassLoading || TraceClassPaths) {
tty->print_cr("[Path %s]", path);
}
}
return new_entry;
}
--- 752,769 ----
THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL);
} else {
return NULL;
}
}
+ }
+ if (TraceClassLoading || TraceClassPaths) {
+ tty->print_cr("[Opened %s]", path);
+ }
} else {
// Directory
new_entry = new ClassPathDirEntry(path);
! if (TraceClassLoading) {
tty->print_cr("[Path %s]", path);
}
}
return new_entry;
}
*** 799,822 ****
--- 882,915 ----
ZipClose = CAST_TO_FN_PTR(ZipClose_t, os::dll_lookup(handle, "ZIP_Close"));
FindEntry = CAST_TO_FN_PTR(FindEntry_t, os::dll_lookup(handle, "ZIP_FindEntry"));
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
if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL ||
GetNextEntry == NULL || Crc32 == NULL) {
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);
}
*** 1366,1376 ****
tty->print_cr("CompileTheWorld : Skipped classes in %s", _dir);
tty->cr();
}
! bool ClassPathDirEntry::is_rt_jar() {
return false;
}
void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) {
real_jzfile* zip = (real_jzfile*) _zip;
--- 1459,1469 ----
tty->print_cr("CompileTheWorld : Skipped classes in %s", _dir);
tty->cr();
}
! bool ClassPathDirEntry::is_jrt() {
return false;
}
void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) {
real_jzfile* zip = (real_jzfile*) _zip;
*** 1391,1417 ****
tty->print_cr("\nCompileTheWorld : Unexpected exception occurred\n");
}
}
}
! bool ClassPathZipEntry::is_rt_jar() {
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);
}
void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) {
ClassPathEntry* cpe = resolve_entry(THREAD);
if (cpe != NULL) {
cpe->compile_the_world(loader, CHECK);
}
}
! bool LazyClassPathEntry::is_rt_jar() {
Thread* THREAD = Thread::current();
ClassPathEntry* cpe = resolve_entry(THREAD);
return (cpe != NULL) ? cpe->is_jar_file() : false;
}
--- 1484,1510 ----
tty->print_cr("\nCompileTheWorld : Unexpected exception occurred\n");
}
}
}
! 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 string_ends_with(zip->name, "rt.jar");
}
void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) {
ClassPathEntry* cpe = resolve_entry(THREAD);
if (cpe != NULL) {
cpe->compile_the_world(loader, CHECK);
}
}
! bool LazyClassPathEntry::is_jrt() {
Thread* THREAD = Thread::current();
ClassPathEntry* cpe = resolve_entry(THREAD);
return (cpe != NULL) ? cpe->is_jar_file() : false;
}
*** 1426,1436 ****
// Iterate over all bootstrap class path entries
ClassPathEntry* e = _first_entry;
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;
e->compile_the_world(system_class_loader, CATCH);
e = e->next();
}
jlong end = os::javaTimeMillis();
tty->print_cr("CompileTheWorld : Done (%d classes, %d methods, " JLONG_FORMAT " ms)",
--- 1519,1529 ----
// Iterate over all bootstrap class path entries
ClassPathEntry* e = _first_entry;
jlong start = os::javaTimeMillis();
while (e != NULL) {
// We stop at rt.jar, unless it is the first bootstrap path entry
! if (e->is_jrt() && e != _first_entry) break;
e->compile_the_world(system_class_loader, CATCH);
e = e->next();
}
jlong end = os::javaTimeMillis();
tty->print_cr("CompileTheWorld : Done (%d classes, %d methods, " JLONG_FORMAT " ms)",
*** 1474,1486 ****
return CompilationPolicy::can_be_compiled(m, comp_level);
}
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) {
// We have a .class file
char buffer[2048];
strncpy(buffer, name, len - 6);
buffer[len-6] = 0;
// If the file has a period after removing .class, it's not really a
// valid class file. The class loader will check everything else.
--- 1567,1579 ----
return CompilationPolicy::can_be_compiled(m, comp_level);
}
void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
! 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;
// If the file has a period after removing .class, it's not really a
// valid class file. The class loader will check everything else.