aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "classfile/classFileParser.hpp" aoqi@0: #include "classfile/classFileStream.hpp" aoqi@0: #include "classfile/classLoader.hpp" iklam@7089: #include "classfile/classLoaderExt.hpp" aoqi@0: #include "classfile/classLoaderData.inline.hpp" aoqi@0: #include "classfile/javaClasses.hpp" iklam@7089: #if INCLUDE_CDS iklam@7089: #include "classfile/sharedPathsMiscInfo.hpp" iklam@7089: #include "classfile/sharedClassUtil.hpp" iklam@7089: #endif aoqi@0: #include "classfile/systemDictionary.hpp" aoqi@0: #include "classfile/vmSymbols.hpp" aoqi@0: #include "compiler/compileBroker.hpp" aoqi@0: #include "gc_interface/collectedHeap.inline.hpp" aoqi@0: #include "interpreter/bytecodeStream.hpp" aoqi@0: #include "interpreter/oopMapCache.hpp" aoqi@0: #include "memory/allocation.inline.hpp" iklam@7089: #include "memory/filemap.hpp" aoqi@0: #include "memory/generation.hpp" aoqi@0: #include "memory/oopFactory.hpp" aoqi@0: #include "memory/universe.inline.hpp" aoqi@0: #include "oops/instanceKlass.hpp" aoqi@0: #include "oops/instanceRefKlass.hpp" aoqi@0: #include "oops/oop.inline.hpp" aoqi@0: #include "oops/symbol.hpp" aoqi@0: #include "prims/jvm_misc.hpp" aoqi@0: #include "runtime/arguments.hpp" aoqi@0: #include "runtime/compilationPolicy.hpp" aoqi@0: #include "runtime/fprofiler.hpp" aoqi@0: #include "runtime/handles.hpp" aoqi@0: #include "runtime/handles.inline.hpp" aoqi@0: #include "runtime/init.hpp" aoqi@0: #include "runtime/interfaceSupport.hpp" aoqi@0: #include "runtime/java.hpp" aoqi@0: #include "runtime/javaCalls.hpp" aoqi@0: #include "runtime/threadCritical.hpp" aoqi@0: #include "runtime/timer.hpp" aoqi@0: #include "services/management.hpp" aoqi@0: #include "services/threadService.hpp" aoqi@0: #include "utilities/events.hpp" aoqi@0: #include "utilities/hashtable.hpp" aoqi@0: #include "utilities/hashtable.inline.hpp" aoqi@0: #ifdef TARGET_OS_FAMILY_linux aoqi@0: # include "os_linux.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_solaris aoqi@0: # include "os_solaris.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_windows aoqi@0: # include "os_windows.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_aix aoqi@0: # include "os_aix.inline.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_OS_FAMILY_bsd aoqi@0: # include "os_bsd.inline.hpp" aoqi@0: #endif aoqi@0: aoqi@0: aoqi@0: // Entry points in zip.dll for loading zip/jar file entries aoqi@0: aoqi@0: typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg); aoqi@0: typedef void (JNICALL *ZipClose_t)(jzfile *zip); aoqi@0: typedef jzentry* (JNICALL *FindEntry_t)(jzfile *zip, const char *name, jint *sizeP, jint *nameLen); aoqi@0: typedef jboolean (JNICALL *ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf); aoqi@0: typedef jboolean (JNICALL *ReadMappedEntry_t)(jzfile *zip, jzentry *entry, unsigned char **buf, char *namebuf); aoqi@0: typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n); aoqi@0: typedef jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len); aoqi@0: aoqi@0: static ZipOpen_t ZipOpen = NULL; aoqi@0: static ZipClose_t ZipClose = NULL; aoqi@0: static FindEntry_t FindEntry = NULL; aoqi@0: static ReadEntry_t ReadEntry = NULL; aoqi@0: static ReadMappedEntry_t ReadMappedEntry = NULL; aoqi@0: static GetNextEntry_t GetNextEntry = NULL; aoqi@0: static canonicalize_fn_t CanonicalizeEntry = NULL; aoqi@0: static Crc32_t Crc32 = NULL; aoqi@0: aoqi@0: // Globals aoqi@0: aoqi@0: PerfCounter* ClassLoader::_perf_accumulated_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_classes_inited = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_init_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_init_selftime = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_classes_verified = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_verify_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_verify_selftime = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_classes_linked = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_link_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_link_selftime = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_parse_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_class_parse_selftime = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_sys_class_lookup_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_shared_classload_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_sys_classload_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_app_classload_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_app_classload_selftime = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_app_classload_count = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_define_appclasses = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_define_appclass_time = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_define_appclass_selftime = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_app_classfile_bytes_read = NULL; aoqi@0: PerfCounter* ClassLoader::_perf_sys_classfile_bytes_read = NULL; aoqi@0: PerfCounter* ClassLoader::_sync_systemLoaderLockContentionRate = NULL; aoqi@0: PerfCounter* ClassLoader::_sync_nonSystemLoaderLockContentionRate = NULL; aoqi@0: PerfCounter* ClassLoader::_sync_JVMFindLoadedClassLockFreeCounter = NULL; aoqi@0: PerfCounter* ClassLoader::_sync_JVMDefineClassLockFreeCounter = NULL; aoqi@0: PerfCounter* ClassLoader::_sync_JNIDefineClassLockFreeCounter = NULL; aoqi@0: PerfCounter* ClassLoader::_unsafe_defineClassCallCounter = NULL; aoqi@0: PerfCounter* ClassLoader::_isUnsyncloadClass = NULL; aoqi@0: PerfCounter* ClassLoader::_load_instance_class_failCounter = NULL; aoqi@0: aoqi@0: ClassPathEntry* ClassLoader::_first_entry = NULL; aoqi@0: ClassPathEntry* ClassLoader::_last_entry = NULL; iklam@7089: int ClassLoader::_num_entries = 0; aoqi@0: PackageHashtable* ClassLoader::_package_hash_table = NULL; aoqi@0: iklam@7089: #if INCLUDE_CDS iklam@7089: SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL; iklam@7089: #endif aoqi@0: // helper routines aoqi@0: bool string_starts_with(const char* str, const char* str_to_find) { aoqi@0: size_t str_len = strlen(str); aoqi@0: size_t str_to_find_len = strlen(str_to_find); aoqi@0: if (str_to_find_len > str_len) { aoqi@0: return false; aoqi@0: } aoqi@0: return (strncmp(str, str_to_find, str_to_find_len) == 0); aoqi@0: } aoqi@0: aoqi@0: bool string_ends_with(const char* str, const char* str_to_find) { aoqi@0: size_t str_len = strlen(str); aoqi@0: size_t str_to_find_len = strlen(str_to_find); aoqi@0: if (str_to_find_len > str_len) { aoqi@0: return false; aoqi@0: } aoqi@0: return (strncmp(str + (str_len - str_to_find_len), str_to_find, str_to_find_len) == 0); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: MetaIndex::MetaIndex(char** meta_package_names, int num_meta_package_names) { aoqi@0: if (num_meta_package_names == 0) { aoqi@0: _meta_package_names = NULL; aoqi@0: _num_meta_package_names = 0; aoqi@0: } else { aoqi@0: _meta_package_names = NEW_C_HEAP_ARRAY(char*, num_meta_package_names, mtClass); aoqi@0: _num_meta_package_names = num_meta_package_names; aoqi@0: memcpy(_meta_package_names, meta_package_names, num_meta_package_names * sizeof(char*)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: MetaIndex::~MetaIndex() { aoqi@0: FREE_C_HEAP_ARRAY(char*, _meta_package_names, mtClass); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool MetaIndex::may_contain(const char* class_name) { aoqi@0: if ( _num_meta_package_names == 0) { aoqi@0: return false; aoqi@0: } aoqi@0: size_t class_name_len = strlen(class_name); aoqi@0: for (int i = 0; i < _num_meta_package_names; i++) { aoqi@0: char* pkg = _meta_package_names[i]; aoqi@0: size_t pkg_len = strlen(pkg); aoqi@0: size_t min_len = MIN2(class_name_len, pkg_len); aoqi@0: if (!strncmp(class_name, pkg, min_len)) { aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: ClassPathEntry::ClassPathEntry() { aoqi@0: set_next(NULL); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool ClassPathEntry::is_lazy() { aoqi@0: return false; aoqi@0: } aoqi@0: iklam@7090: ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() { iklam@7090: char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass); iklam@7090: strcpy(copy, dir); iklam@7090: _dir = copy; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) { aoqi@0: // construct full path name aoqi@0: char path[JVM_MAXPATHLEN]; aoqi@0: if (jio_snprintf(path, sizeof(path), "%s%s%s", _dir, os::file_separator(), name) == -1) { aoqi@0: return NULL; aoqi@0: } aoqi@0: // check if file exists aoqi@0: struct stat st; aoqi@0: if (os::stat(path, &st) == 0) { iklam@7089: #if INCLUDE_CDS iklam@7089: if (DumpSharedSpaces) { iklam@7089: // We have already check in ClassLoader::check_shared_classpath() that the directory is empty, so iklam@7089: // we should never find a file underneath it -- unless user has added a new file while we are running iklam@7089: // the dump, in which case let's quit! iklam@7089: ShouldNotReachHere(); iklam@7089: } iklam@7089: #endif aoqi@0: // found file, open it aoqi@0: int file_handle = os::open(path, 0, 0); aoqi@0: if (file_handle != -1) { aoqi@0: // read contents into resource array aoqi@0: u1* buffer = NEW_RESOURCE_ARRAY(u1, st.st_size); aoqi@0: size_t num_read = os::read(file_handle, (char*) buffer, st.st_size); aoqi@0: // close file aoqi@0: os::close(file_handle); aoqi@0: // construct ClassFileStream aoqi@0: if (num_read == (size_t)st.st_size) { aoqi@0: if (UsePerfData) { aoqi@0: ClassLoader::perf_sys_classfile_bytes_read()->inc(num_read); aoqi@0: } aoqi@0: return new ClassFileStream(buffer, st.st_size, _dir); // Resource allocated aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() { aoqi@0: _zip = zip; iklam@7090: char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass); iklam@7090: strcpy(copy, zip_name); iklam@7090: _zip_name = copy; aoqi@0: } aoqi@0: aoqi@0: ClassPathZipEntry::~ClassPathZipEntry() { aoqi@0: if (ZipClose != NULL) { aoqi@0: (*ZipClose)(_zip); aoqi@0: } aoqi@0: FREE_C_HEAP_ARRAY(char, _zip_name, mtClass); aoqi@0: } aoqi@0: iklam@7089: u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) { iklam@7089: // enable call to C land aoqi@0: JavaThread* thread = JavaThread::current(); aoqi@0: ThreadToNativeFromVM ttn(thread); aoqi@0: // check whether zip archive contains name iklam@7089: jint name_len; iklam@7089: jzentry* entry = (*FindEntry)(_zip, name, filesize, &name_len); aoqi@0: if (entry == NULL) return NULL; aoqi@0: u1* buffer; aoqi@0: char name_buf[128]; aoqi@0: char* filename; aoqi@0: if (name_len < 128) { aoqi@0: filename = name_buf; aoqi@0: } else { aoqi@0: filename = NEW_RESOURCE_ARRAY(char, name_len + 1); aoqi@0: } aoqi@0: iklam@7089: // file found, get pointer to the entry in mmapped jar file. aoqi@0: if (ReadMappedEntry == NULL || aoqi@0: !(*ReadMappedEntry)(_zip, entry, &buffer, filename)) { iklam@7089: // mmapped access not available, perhaps due to compression, aoqi@0: // read contents into resource array iklam@7089: int size = (*filesize) + ((nul_terminate) ? 1 : 0); iklam@7089: buffer = NEW_RESOURCE_ARRAY(u1, size); aoqi@0: if (!(*ReadEntry)(_zip, entry, buffer, filename)) return NULL; aoqi@0: } iklam@7089: iklam@7089: // return result iklam@7089: if (nul_terminate) { iklam@7089: buffer[*filesize] = 0; iklam@7089: } iklam@7089: return buffer; iklam@7089: } iklam@7089: iklam@7089: ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) { iklam@7089: jint filesize; iklam@7089: u1* buffer = open_entry(name, &filesize, false, CHECK_NULL); iklam@7089: if (buffer == NULL) { iklam@7089: return NULL; iklam@7089: } aoqi@0: if (UsePerfData) { aoqi@0: ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize); aoqi@0: } iklam@7089: return new ClassFileStream(buffer, filesize, _zip_name); // Resource allocated aoqi@0: } aoqi@0: aoqi@0: // invoke function for each entry in the zip file aoqi@0: void ClassPathZipEntry::contents_do(void f(const char* name, void* context), void* context) { aoqi@0: JavaThread* thread = JavaThread::current(); aoqi@0: HandleMark handle_mark(thread); aoqi@0: ThreadToNativeFromVM ttn(thread); aoqi@0: for (int n = 0; ; n++) { aoqi@0: jzentry * ze = ((*GetNextEntry)(_zip, n)); aoqi@0: if (ze == NULL) break; aoqi@0: (*f)(ze->name, context); aoqi@0: } aoqi@0: } aoqi@0: iklam@7090: LazyClassPathEntry::LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() { aoqi@0: _path = strdup(path); aoqi@0: _st = *st; aoqi@0: _meta_index = NULL; aoqi@0: _resolved_entry = NULL; aoqi@0: _has_error = false; iklam@7089: _throw_exception = throw_exception; aoqi@0: } aoqi@0: aoqi@0: bool LazyClassPathEntry::is_jar_file() { aoqi@0: return ((_st.st_mode & S_IFREG) == S_IFREG); aoqi@0: } aoqi@0: aoqi@0: ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) { aoqi@0: if (_resolved_entry != NULL) { aoqi@0: return (ClassPathEntry*) _resolved_entry; aoqi@0: } aoqi@0: ClassPathEntry* new_entry = NULL; iklam@7089: new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, _throw_exception, CHECK_NULL); iklam@7089: if (!_throw_exception && new_entry == NULL) { iklam@7089: assert(!HAS_PENDING_EXCEPTION, "must be"); iklam@7089: return NULL; iklam@7089: } aoqi@0: { aoqi@0: ThreadCritical tc; aoqi@0: if (_resolved_entry == NULL) { aoqi@0: _resolved_entry = new_entry; aoqi@0: return new_entry; aoqi@0: } aoqi@0: } aoqi@0: assert(_resolved_entry != NULL, "bug in MT-safe resolution logic"); aoqi@0: delete new_entry; aoqi@0: return (ClassPathEntry*) _resolved_entry; aoqi@0: } aoqi@0: aoqi@0: ClassFileStream* LazyClassPathEntry::open_stream(const char* name, TRAPS) { aoqi@0: if (_meta_index != NULL && aoqi@0: !_meta_index->may_contain(name)) { aoqi@0: return NULL; aoqi@0: } aoqi@0: if (_has_error) { aoqi@0: return NULL; aoqi@0: } aoqi@0: ClassPathEntry* cpe = resolve_entry(THREAD); aoqi@0: if (cpe == NULL) { aoqi@0: _has_error = true; aoqi@0: return NULL; aoqi@0: } else { aoqi@0: return cpe->open_stream(name, THREAD); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool LazyClassPathEntry::is_lazy() { aoqi@0: return true; aoqi@0: } aoqi@0: iklam@7089: u1* LazyClassPathEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) { iklam@7089: if (_has_error) { iklam@7089: return NULL; iklam@7089: } iklam@7089: ClassPathEntry* cpe = resolve_entry(THREAD); iklam@7089: if (cpe == NULL) { iklam@7089: _has_error = true; iklam@7089: return NULL; iklam@7089: } else if (cpe->is_jar_file()) { iklam@7089: return ((ClassPathZipEntry*)cpe)->open_entry(name, filesize, nul_terminate,THREAD); iklam@7089: } else { iklam@7089: ShouldNotReachHere(); iklam@7089: *filesize = 0; iklam@7089: return NULL; iklam@7089: } iklam@7089: } iklam@7089: aoqi@0: static void print_meta_index(LazyClassPathEntry* entry, aoqi@0: GrowableArray& meta_packages) { aoqi@0: tty->print("[Meta index for %s=", entry->name()); aoqi@0: for (int i = 0; i < meta_packages.length(); i++) { aoqi@0: if (i > 0) tty->print(" "); aoqi@0: tty->print("%s", meta_packages.at(i)); aoqi@0: } aoqi@0: tty->print_cr("]"); aoqi@0: } aoqi@0: iklam@7089: #if INCLUDE_CDS iklam@7089: void ClassLoader::exit_with_path_failure(const char* error, const char* message) { iklam@7089: assert(DumpSharedSpaces, "only called at dump time"); iklam@7089: tty->print_cr("Hint: enable -XX:+TraceClassPaths to diagnose the failure"); iklam@7089: vm_exit_during_initialization(error, message); iklam@7089: } iklam@7089: #endif aoqi@0: iklam@7089: void ClassLoader::trace_class_path(const char* msg, const char* name) { iklam@7089: if (!TraceClassPaths) { iklam@7089: return; iklam@7089: } iklam@7089: iklam@7089: if (msg) { iklam@7089: tty->print("%s", msg); iklam@7089: } iklam@7089: if (name) { iklam@7089: if (strlen(name) < 256) { iklam@7089: tty->print("%s", name); iklam@7089: } else { iklam@7089: // For very long paths, we need to print each character separately, iklam@7089: // as print_cr() has a length limit iklam@7089: while (name[0] != '\0') { iklam@7089: tty->print("%c", name[0]); iklam@7089: name++; iklam@7089: } iklam@7089: } iklam@7089: } iklam@7089: if (msg && msg[0] == '[') { iklam@7089: tty->print_cr("]"); iklam@7089: } else { iklam@7089: tty->cr(); iklam@7089: } iklam@7089: } iklam@7089: iklam@7089: void ClassLoader::setup_bootstrap_meta_index() { aoqi@0: // Set up meta index which allows us to open boot jars lazily if aoqi@0: // class data sharing is enabled iklam@7089: const char* meta_index_path = Arguments::get_meta_index_path(); iklam@7089: const char* meta_index_dir = Arguments::get_meta_index_dir(); iklam@7089: setup_meta_index(meta_index_path, meta_index_dir, 0); iklam@7089: } iklam@7089: iklam@7089: void ClassLoader::setup_meta_index(const char* meta_index_path, const char* meta_index_dir, int start_index) { aoqi@0: const char* known_version = "% VERSION 2"; aoqi@0: FILE* file = fopen(meta_index_path, "r"); aoqi@0: int line_no = 0; iklam@7089: #if INCLUDE_CDS iklam@7089: if (DumpSharedSpaces) { iklam@7089: if (file != NULL) { iklam@7089: _shared_paths_misc_info->add_required_file(meta_index_path); iklam@7089: } else { iklam@7089: _shared_paths_misc_info->add_nonexist_path(meta_index_path); iklam@7089: } iklam@7089: } iklam@7089: #endif aoqi@0: if (file != NULL) { aoqi@0: ResourceMark rm; aoqi@0: LazyClassPathEntry* cur_entry = NULL; aoqi@0: GrowableArray boot_class_path_packages(10); aoqi@0: char package_name[256]; aoqi@0: bool skipCurrentJar = false; aoqi@0: while (fgets(package_name, sizeof(package_name), file) != NULL) { aoqi@0: ++line_no; aoqi@0: // Remove trailing newline aoqi@0: package_name[strlen(package_name) - 1] = '\0'; aoqi@0: switch(package_name[0]) { aoqi@0: case '%': aoqi@0: { aoqi@0: if ((line_no == 1) && (strcmp(package_name, known_version) != 0)) { aoqi@0: if (TraceClassLoading && Verbose) { aoqi@0: tty->print("[Unsupported meta index version]"); aoqi@0: } aoqi@0: fclose(file); aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // These directives indicate jar files which contain only aoqi@0: // classes, only non-classfile resources, or a combination of aoqi@0: // the two. See src/share/classes/sun/misc/MetaIndex.java and aoqi@0: // make/tools/MetaIndex/BuildMetaIndex.java in the J2SE aoqi@0: // workspace. aoqi@0: case '#': aoqi@0: case '!': aoqi@0: case '@': aoqi@0: { aoqi@0: // Hand off current packages to current lazy entry (if any) aoqi@0: if ((cur_entry != NULL) && aoqi@0: (boot_class_path_packages.length() > 0)) { iklam@7089: if ((TraceClassLoading || TraceClassPaths) && Verbose) { aoqi@0: print_meta_index(cur_entry, boot_class_path_packages); aoqi@0: } aoqi@0: MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0), aoqi@0: boot_class_path_packages.length()); aoqi@0: cur_entry->set_meta_index(index); aoqi@0: } aoqi@0: cur_entry = NULL; aoqi@0: boot_class_path_packages.clear(); aoqi@0: aoqi@0: // Find lazy entry corresponding to this jar file iklam@7089: int count = 0; iklam@7089: for (ClassPathEntry* entry = _first_entry; entry != NULL; entry = entry->next(), count++) { iklam@7089: if (count >= start_index && iklam@7089: entry->is_lazy() && aoqi@0: string_starts_with(entry->name(), meta_index_dir) && aoqi@0: string_ends_with(entry->name(), &package_name[2])) { aoqi@0: cur_entry = (LazyClassPathEntry*) entry; aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // If the first character is '@', it indicates the following jar aoqi@0: // file is a resource only jar file in which case, we should skip aoqi@0: // reading the subsequent entries since the resource loading is aoqi@0: // totally handled by J2SE side. aoqi@0: if (package_name[0] == '@') { aoqi@0: if (cur_entry != NULL) { aoqi@0: cur_entry->set_meta_index(new MetaIndex(NULL, 0)); aoqi@0: } aoqi@0: cur_entry = NULL; aoqi@0: skipCurrentJar = true; aoqi@0: } else { aoqi@0: skipCurrentJar = false; aoqi@0: } aoqi@0: aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: default: aoqi@0: { aoqi@0: if (!skipCurrentJar && cur_entry != NULL) { aoqi@0: char* new_name = strdup(package_name); aoqi@0: boot_class_path_packages.append(new_name); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: // Hand off current packages to current lazy entry (if any) aoqi@0: if ((cur_entry != NULL) && aoqi@0: (boot_class_path_packages.length() > 0)) { iklam@7089: if ((TraceClassLoading || TraceClassPaths) && Verbose) { aoqi@0: print_meta_index(cur_entry, boot_class_path_packages); aoqi@0: } aoqi@0: MetaIndex* index = new MetaIndex(boot_class_path_packages.adr_at(0), aoqi@0: boot_class_path_packages.length()); aoqi@0: cur_entry->set_meta_index(index); aoqi@0: } aoqi@0: fclose(file); aoqi@0: } aoqi@0: } aoqi@0: iklam@7089: #if INCLUDE_CDS iklam@7089: void ClassLoader::check_shared_classpath(const char *path) { iklam@7089: if (strcmp(path, "") == 0) { iklam@7089: exit_with_path_failure("Cannot have empty path in archived classpaths", NULL); iklam@7089: } iklam@7089: iklam@7089: struct stat st; iklam@7089: if (os::stat(path, &st) == 0) { iklam@7089: if ((st.st_mode & S_IFREG) != S_IFREG) { // is directory iklam@7089: if (!os::dir_is_empty(path)) { iklam@7089: tty->print_cr("Error: non-empty directory '%s'", path); iklam@7089: exit_with_path_failure("CDS allows only empty directories in archived classpaths", NULL); iklam@7089: } iklam@7089: } iklam@7089: } iklam@7089: } iklam@7089: #endif iklam@7089: aoqi@0: void ClassLoader::setup_bootstrap_search_path() { aoqi@0: assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); iklam@7090: const char* sys_class_path = Arguments::get_sysclasspath(); iklam@7090: if (PrintSharedArchiveAndExit) { iklam@7090: // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily iklam@7090: // the same as the bootcp of the shared archive. iklam@7090: } else { iklam@7089: trace_class_path("[Bootstrap loader class path=", sys_class_path); aoqi@0: } iklam@7089: #if INCLUDE_CDS iklam@7089: if (DumpSharedSpaces) { iklam@7090: _shared_paths_misc_info->add_boot_classpath(sys_class_path); iklam@7089: } iklam@7089: #endif iklam@7089: setup_search_path(sys_class_path); iklam@7089: } aoqi@0: iklam@7089: #if INCLUDE_CDS iklam@7089: int ClassLoader::get_shared_paths_misc_info_size() { iklam@7089: return _shared_paths_misc_info->get_used_bytes(); iklam@7089: } iklam@7089: iklam@7089: void* ClassLoader::get_shared_paths_misc_info() { iklam@7089: return _shared_paths_misc_info->buffer(); iklam@7089: } iklam@7089: iklam@7089: bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) { iklam@7089: SharedPathsMiscInfo* checker = SharedClassUtil::allocate_shared_paths_misc_info((char*)buf, size); iklam@7089: bool result = checker->check(); iklam@7089: delete checker; iklam@7089: return result; iklam@7089: } iklam@7089: #endif iklam@7089: iklam@7322: void ClassLoader::setup_search_path(const char *class_path, bool canonicalize) { iklam@7089: int offset = 0; iklam@7089: int len = (int)strlen(class_path); aoqi@0: int end = 0; aoqi@0: aoqi@0: // Iterate over class path entries aoqi@0: for (int start = 0; start < len; start = end) { iklam@7089: while (class_path[end] && class_path[end] != os::path_separator()[0]) { aoqi@0: end++; aoqi@0: } iklam@7089: EXCEPTION_MARK; iklam@7089: ResourceMark rm(THREAD); iklam@7089: char* path = NEW_RESOURCE_ARRAY(char, end - start + 1); iklam@7089: strncpy(path, &class_path[start], end - start); iklam@7089: path[end - start] = '\0'; iklam@7322: if (canonicalize) { iklam@7322: char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN + 1); iklam@7322: if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { iklam@7322: path = canonical_path; iklam@7322: } iklam@7322: } iklam@7322: update_class_path_entry_list(path, /*check_for_duplicates=*/canonicalize); iklam@7089: #if INCLUDE_CDS iklam@7089: if (DumpSharedSpaces) { iklam@7089: check_shared_classpath(path); iklam@7089: } iklam@7089: #endif iklam@7089: while (class_path[end] == os::path_separator()[0]) { aoqi@0: end++; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: iklam@7090: ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st, iklam@7089: bool lazy, bool throw_exception, TRAPS) { aoqi@0: JavaThread* thread = JavaThread::current(); aoqi@0: if (lazy) { iklam@7089: return new LazyClassPathEntry(path, st, throw_exception); aoqi@0: } aoqi@0: ClassPathEntry* new_entry = NULL; aoqi@0: if ((st->st_mode & S_IFREG) == S_IFREG) { aoqi@0: // Regular file, should be a zip file aoqi@0: // Canonicalized filename aoqi@0: char canonical_path[JVM_MAXPATHLEN]; aoqi@0: if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { aoqi@0: // This matches the classic VM iklam@7089: if (throw_exception) { iklam@7089: THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL); iklam@7089: } else { iklam@7089: return NULL; iklam@7089: } aoqi@0: } aoqi@0: char* error_msg = NULL; aoqi@0: jzfile* zip; aoqi@0: { aoqi@0: // enable call to C land aoqi@0: ThreadToNativeFromVM ttn(thread); aoqi@0: HandleMark hm(thread); aoqi@0: zip = (*ZipOpen)(canonical_path, &error_msg); aoqi@0: } aoqi@0: if (zip != NULL && error_msg == NULL) { aoqi@0: new_entry = new ClassPathZipEntry(zip, path); iklam@7089: if (TraceClassLoading || TraceClassPaths) { aoqi@0: tty->print_cr("[Opened %s]", path); aoqi@0: } aoqi@0: } else { aoqi@0: ResourceMark rm(thread); aoqi@0: char *msg; aoqi@0: if (error_msg == NULL) { aoqi@0: msg = NEW_RESOURCE_ARRAY(char, strlen(path) + 128); ; aoqi@0: jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); aoqi@0: } else { aoqi@0: int len = (int)(strlen(path) + strlen(error_msg) + 128); aoqi@0: msg = NEW_RESOURCE_ARRAY(char, len); ; aoqi@0: jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path); aoqi@0: } iklam@7089: if (throw_exception) { iklam@7089: THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL); iklam@7089: } else { iklam@7089: return NULL; iklam@7089: } aoqi@0: } aoqi@0: } else { aoqi@0: // Directory aoqi@0: new_entry = new ClassPathDirEntry(path); iklam@7089: if (TraceClassLoading || TraceClassPaths) { aoqi@0: tty->print_cr("[Path %s]", path); aoqi@0: } aoqi@0: } aoqi@0: return new_entry; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Create a class path zip entry for a given path (return NULL if not found aoqi@0: // or zip/JAR file cannot be opened) aoqi@0: ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) { aoqi@0: // check for a regular file aoqi@0: struct stat st; aoqi@0: if (os::stat(path, &st) == 0) { aoqi@0: if ((st.st_mode & S_IFREG) == S_IFREG) { aoqi@0: char canonical_path[JVM_MAXPATHLEN]; iklam@7090: if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { aoqi@0: char* error_msg = NULL; aoqi@0: jzfile* zip; aoqi@0: { aoqi@0: // enable call to C land aoqi@0: JavaThread* thread = JavaThread::current(); aoqi@0: ThreadToNativeFromVM ttn(thread); aoqi@0: HandleMark hm(thread); aoqi@0: zip = (*ZipOpen)(canonical_path, &error_msg); aoqi@0: } aoqi@0: if (zip != NULL && error_msg == NULL) { aoqi@0: // create using canonical path aoqi@0: return new ClassPathZipEntry(zip, canonical_path); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: // returns true if entry already on class path aoqi@0: bool ClassLoader::contains_entry(ClassPathEntry *entry) { aoqi@0: ClassPathEntry* e = _first_entry; aoqi@0: while (e != NULL) { aoqi@0: // assume zip entries have been canonicalized aoqi@0: if (strcmp(entry->name(), e->name()) == 0) { aoqi@0: return true; aoqi@0: } aoqi@0: e = e->next(); aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: void ClassLoader::add_to_list(ClassPathEntry *new_entry) { aoqi@0: if (new_entry != NULL) { aoqi@0: if (_last_entry == NULL) { aoqi@0: _first_entry = _last_entry = new_entry; aoqi@0: } else { aoqi@0: _last_entry->set_next(new_entry); aoqi@0: _last_entry = new_entry; aoqi@0: } aoqi@0: } iklam@7089: _num_entries ++; aoqi@0: } aoqi@0: iklam@7089: // Returns true IFF the file/dir exists and the entry was successfully created. iklam@7090: bool ClassLoader::update_class_path_entry_list(const char *path, iklam@7089: bool check_for_duplicates, iklam@7089: bool throw_exception) { aoqi@0: struct stat st; aoqi@0: if (os::stat(path, &st) == 0) { aoqi@0: // File or directory found aoqi@0: ClassPathEntry* new_entry = NULL; aoqi@0: Thread* THREAD = Thread::current(); iklam@7089: new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, throw_exception, CHECK_(false)); iklam@7089: if (new_entry == NULL) { iklam@7089: return false; iklam@7089: } aoqi@0: // The kernel VM adds dynamically to the end of the classloader path and aoqi@0: // doesn't reorder the bootclasspath which would break java.lang.Package aoqi@0: // (see PackageInfo). aoqi@0: // Add new entry to linked list aoqi@0: if (!check_for_duplicates || !contains_entry(new_entry)) { iklam@7089: ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry); aoqi@0: } iklam@7089: return true; iklam@7089: } else { iklam@7089: #if INCLUDE_CDS iklam@7089: if (DumpSharedSpaces) { iklam@7089: _shared_paths_misc_info->add_nonexist_path(path); iklam@7089: } iklam@7090: #endif iklam@7089: return false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void ClassLoader::print_bootclasspath() { aoqi@0: ClassPathEntry* e = _first_entry; aoqi@0: tty->print("[bootclasspath= "); aoqi@0: while (e != NULL) { aoqi@0: tty->print("%s ;", e->name()); aoqi@0: e = e->next(); aoqi@0: } aoqi@0: tty->print_cr("]"); aoqi@0: } aoqi@0: aoqi@0: void ClassLoader::load_zip_library() { aoqi@0: assert(ZipOpen == NULL, "should not load zip library twice"); aoqi@0: // First make sure native library is loaded aoqi@0: os::native_java_library(); aoqi@0: // Load zip library aoqi@0: char path[JVM_MAXPATHLEN]; aoqi@0: char ebuf[1024]; aoqi@0: void* handle = NULL; aoqi@0: if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "zip")) { aoqi@0: handle = os::dll_load(path, ebuf, sizeof ebuf); aoqi@0: } aoqi@0: if (handle == NULL) { aoqi@0: vm_exit_during_initialization("Unable to load ZIP library", path); aoqi@0: } aoqi@0: // Lookup zip entry points aoqi@0: ZipOpen = CAST_TO_FN_PTR(ZipOpen_t, os::dll_lookup(handle, "ZIP_Open")); aoqi@0: ZipClose = CAST_TO_FN_PTR(ZipClose_t, os::dll_lookup(handle, "ZIP_Close")); aoqi@0: FindEntry = CAST_TO_FN_PTR(FindEntry_t, os::dll_lookup(handle, "ZIP_FindEntry")); aoqi@0: ReadEntry = CAST_TO_FN_PTR(ReadEntry_t, os::dll_lookup(handle, "ZIP_ReadEntry")); aoqi@0: ReadMappedEntry = CAST_TO_FN_PTR(ReadMappedEntry_t, os::dll_lookup(handle, "ZIP_ReadMappedEntry")); aoqi@0: GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, os::dll_lookup(handle, "ZIP_GetNextEntry")); aoqi@0: Crc32 = CAST_TO_FN_PTR(Crc32_t, os::dll_lookup(handle, "ZIP_CRC32")); aoqi@0: aoqi@0: // ZIP_Close is not exported on Windows in JDK5.0 so don't abort if ZIP_Close is NULL aoqi@0: if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL || aoqi@0: GetNextEntry == NULL || Crc32 == NULL) { aoqi@0: vm_exit_during_initialization("Corrupted ZIP library", path); aoqi@0: } aoqi@0: aoqi@0: // Lookup canonicalize entry in libjava.dll aoqi@0: void *javalib_handle = os::native_java_library(); aoqi@0: CanonicalizeEntry = CAST_TO_FN_PTR(canonicalize_fn_t, os::dll_lookup(javalib_handle, "Canonicalize")); aoqi@0: // This lookup only works on 1.3. Do not check for non-null here aoqi@0: } aoqi@0: aoqi@0: int ClassLoader::crc32(int crc, const char* buf, int len) { aoqi@0: assert(Crc32 != NULL, "ZIP_CRC32 is not found"); aoqi@0: return (*Crc32)(crc, (const jbyte*)buf, len); aoqi@0: } aoqi@0: aoqi@0: // PackageInfo data exists in order to support the java.lang.Package aoqi@0: // class. A Package object provides information about a java package aoqi@0: // (version, vendor, etc.) which originates in the manifest of the jar aoqi@0: // file supplying the package. For application classes, the ClassLoader aoqi@0: // object takes care of this. aoqi@0: aoqi@0: // For system (boot) classes, the Java code in the Package class needs aoqi@0: // to be able to identify which source jar file contained the boot aoqi@0: // class, so that it can extract the manifest from it. This table aoqi@0: // identifies java packages with jar files in the boot classpath. aoqi@0: aoqi@0: // Because the boot classpath cannot change, the classpath index is aoqi@0: // sufficient to identify the source jar file or directory. (Since aoqi@0: // directories have no manifests, the directory name is not required, aoqi@0: // but is available.) aoqi@0: aoqi@0: // When using sharing -- the pathnames of entries in the boot classpath aoqi@0: // may not be the same at runtime as they were when the archive was aoqi@0: // created (NFS, Samba, etc.). The actual files and directories named aoqi@0: // in the classpath must be the same files, in the same order, even aoqi@0: // though the exact name is not the same. aoqi@0: aoqi@0: class PackageInfo: public BasicHashtableEntry { aoqi@0: public: aoqi@0: const char* _pkgname; // Package name aoqi@0: int _classpath_index; // Index of directory or JAR file loaded from aoqi@0: aoqi@0: PackageInfo* next() { aoqi@0: return (PackageInfo*)BasicHashtableEntry::next(); aoqi@0: } aoqi@0: aoqi@0: const char* pkgname() { return _pkgname; } aoqi@0: void set_pkgname(char* pkgname) { _pkgname = pkgname; } aoqi@0: aoqi@0: const char* filename() { aoqi@0: return ClassLoader::classpath_entry(_classpath_index)->name(); aoqi@0: } aoqi@0: aoqi@0: void set_index(int index) { aoqi@0: _classpath_index = index; aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: class PackageHashtable : public BasicHashtable { aoqi@0: private: aoqi@0: inline unsigned int compute_hash(const char *s, int n) { aoqi@0: unsigned int val = 0; aoqi@0: while (--n >= 0) { aoqi@0: val = *s++ + 31 * val; aoqi@0: } aoqi@0: return val; aoqi@0: } aoqi@0: aoqi@0: PackageInfo* bucket(int index) { aoqi@0: return (PackageInfo*)BasicHashtable::bucket(index); aoqi@0: } aoqi@0: aoqi@0: PackageInfo* get_entry(int index, unsigned int hash, aoqi@0: const char* pkgname, size_t n) { aoqi@0: for (PackageInfo* pp = bucket(index); pp != NULL; pp = pp->next()) { aoqi@0: if (pp->hash() == hash && aoqi@0: strncmp(pkgname, pp->pkgname(), n) == 0 && aoqi@0: pp->pkgname()[n] == '\0') { aoqi@0: return pp; aoqi@0: } aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: public: aoqi@0: PackageHashtable(int table_size) aoqi@0: : BasicHashtable(table_size, sizeof(PackageInfo)) {} aoqi@0: aoqi@0: PackageHashtable(int table_size, HashtableBucket* t, int number_of_entries) aoqi@0: : BasicHashtable(table_size, sizeof(PackageInfo), t, number_of_entries) {} aoqi@0: aoqi@0: PackageInfo* get_entry(const char* pkgname, int n) { aoqi@0: unsigned int hash = compute_hash(pkgname, n); aoqi@0: return get_entry(hash_to_index(hash), hash, pkgname, n); aoqi@0: } aoqi@0: aoqi@0: PackageInfo* new_entry(char* pkgname, int n) { aoqi@0: unsigned int hash = compute_hash(pkgname, n); aoqi@0: PackageInfo* pp; aoqi@0: pp = (PackageInfo*)BasicHashtable::new_entry(hash); aoqi@0: pp->set_pkgname(pkgname); aoqi@0: return pp; aoqi@0: } aoqi@0: aoqi@0: void add_entry(PackageInfo* pp) { aoqi@0: int index = hash_to_index(pp->hash()); aoqi@0: BasicHashtable::add_entry(index, pp); aoqi@0: } aoqi@0: aoqi@0: void copy_pkgnames(const char** packages) { aoqi@0: int n = 0; aoqi@0: for (int i = 0; i < table_size(); ++i) { aoqi@0: for (PackageInfo* pp = bucket(i); pp != NULL; pp = pp->next()) { aoqi@0: packages[n++] = pp->pkgname(); aoqi@0: } aoqi@0: } aoqi@0: assert(n == number_of_entries(), "just checking"); aoqi@0: } aoqi@0: iklam@7089: CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);) aoqi@0: }; aoqi@0: iklam@7089: #if INCLUDE_CDS aoqi@0: void PackageHashtable::copy_table(char** top, char* end, aoqi@0: PackageHashtable* table) { aoqi@0: // Copy (relocate) the table to the shared space. aoqi@0: BasicHashtable::copy_table(top, end); aoqi@0: aoqi@0: // Calculate the space needed for the package name strings. aoqi@0: int i; iklam@7089: intptr_t* tableSize = (intptr_t*)(*top); iklam@7089: *top += sizeof(intptr_t); // For table size iklam@7089: char* tableStart = *top; aoqi@0: aoqi@0: for (i = 0; i < table_size(); ++i) { aoqi@0: for (PackageInfo* pp = table->bucket(i); aoqi@0: pp != NULL; aoqi@0: pp = pp->next()) { aoqi@0: int n1 = (int)(strlen(pp->pkgname()) + 1); iklam@7089: if (*top + n1 >= end) { iklam@7089: report_out_of_shared_space(SharedMiscData); iklam@7089: } aoqi@0: pp->set_pkgname((char*)memcpy(*top, pp->pkgname(), n1)); aoqi@0: *top += n1; aoqi@0: } aoqi@0: } aoqi@0: *top = (char*)align_size_up((intptr_t)*top, sizeof(HeapWord)); iklam@7089: if (*top >= end) { iklam@7089: report_out_of_shared_space(SharedMiscData); iklam@7089: } iklam@7089: iklam@7089: // Write table size iklam@7089: intptr_t len = *top - (char*)tableStart; iklam@7089: *tableSize = len; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void ClassLoader::copy_package_info_buckets(char** top, char* end) { aoqi@0: _package_hash_table->copy_buckets(top, end); aoqi@0: } aoqi@0: aoqi@0: void ClassLoader::copy_package_info_table(char** top, char* end) { aoqi@0: _package_hash_table->copy_table(top, end, _package_hash_table); aoqi@0: } iklam@7089: #endif aoqi@0: aoqi@0: PackageInfo* ClassLoader::lookup_package(const char *pkgname) { aoqi@0: const char *cp = strrchr(pkgname, '/'); aoqi@0: if (cp != NULL) { aoqi@0: // Package prefix found aoqi@0: int n = cp - pkgname + 1; aoqi@0: return _package_hash_table->get_entry(pkgname, n); aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool ClassLoader::add_package(const char *pkgname, int classpath_index, TRAPS) { aoqi@0: assert(pkgname != NULL, "just checking"); aoqi@0: // Bootstrap loader no longer holds system loader lock obj serializing aoqi@0: // load_instance_class and thereby add_package aoqi@0: { aoqi@0: MutexLocker ml(PackageTable_lock, THREAD); aoqi@0: // First check for previously loaded entry aoqi@0: PackageInfo* pp = lookup_package(pkgname); aoqi@0: if (pp != NULL) { aoqi@0: // Existing entry found, check source of package aoqi@0: pp->set_index(classpath_index); aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: const char *cp = strrchr(pkgname, '/'); aoqi@0: if (cp != NULL) { aoqi@0: // Package prefix found aoqi@0: int n = cp - pkgname + 1; aoqi@0: aoqi@0: char* new_pkgname = NEW_C_HEAP_ARRAY(char, n + 1, mtClass); aoqi@0: if (new_pkgname == NULL) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: memcpy(new_pkgname, pkgname, n); aoqi@0: new_pkgname[n] = '\0'; aoqi@0: pp = _package_hash_table->new_entry(new_pkgname, n); aoqi@0: pp->set_index(classpath_index); aoqi@0: aoqi@0: // Insert into hash table aoqi@0: _package_hash_table->add_entry(pp); aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: oop ClassLoader::get_system_package(const char* name, TRAPS) { aoqi@0: PackageInfo* pp; aoqi@0: { aoqi@0: MutexLocker ml(PackageTable_lock, THREAD); aoqi@0: pp = lookup_package(name); aoqi@0: } aoqi@0: if (pp == NULL) { aoqi@0: return NULL; aoqi@0: } else { aoqi@0: Handle p = java_lang_String::create_from_str(pp->filename(), THREAD); aoqi@0: return p(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: objArrayOop ClassLoader::get_system_packages(TRAPS) { aoqi@0: ResourceMark rm(THREAD); aoqi@0: int nof_entries; aoqi@0: const char** packages; aoqi@0: { aoqi@0: MutexLocker ml(PackageTable_lock, THREAD); aoqi@0: // Allocate resource char* array containing package names aoqi@0: nof_entries = _package_hash_table->number_of_entries(); aoqi@0: if ((packages = NEW_RESOURCE_ARRAY(const char*, nof_entries)) == NULL) { aoqi@0: return NULL; aoqi@0: } aoqi@0: _package_hash_table->copy_pkgnames(packages); aoqi@0: } aoqi@0: // Allocate objArray and fill with java.lang.String aoqi@0: objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), aoqi@0: nof_entries, CHECK_0); aoqi@0: objArrayHandle result(THREAD, r); aoqi@0: for (int i = 0; i < nof_entries; i++) { aoqi@0: Handle str = java_lang_String::create_from_str(packages[i], CHECK_0); aoqi@0: result->obj_at_put(i, str()); aoqi@0: } aoqi@0: aoqi@0: return result(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { aoqi@0: ResourceMark rm(THREAD); iklam@7089: const char* class_name = h_name->as_C_string(); iklam@7089: EventMark m("loading class %s", class_name); aoqi@0: ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion); aoqi@0: aoqi@0: stringStream st; aoqi@0: // st.print() uses too much stack space while handling a StackOverflowError aoqi@0: // st.print("%s.class", h_name->as_utf8()); aoqi@0: st.print_raw(h_name->as_utf8()); aoqi@0: st.print_raw(".class"); iklam@7089: const char* file_name = st.as_string(); iklam@7089: ClassLoaderExt::Context context(class_name, file_name, THREAD); aoqi@0: aoqi@0: // Lookup stream for parsing .class file aoqi@0: ClassFileStream* stream = NULL; aoqi@0: int classpath_index = 0; iklam@7089: ClassPathEntry* e = NULL; iklam@7089: instanceKlassHandle h; aoqi@0: { aoqi@0: PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), aoqi@0: ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(), aoqi@0: PerfClassTraceTime::CLASS_LOAD); iklam@7089: e = _first_entry; aoqi@0: while (e != NULL) { iklam@7089: stream = e->open_stream(file_name, CHECK_NULL); iklam@7089: if (!context.check(stream, classpath_index)) { iklam@7089: return h; // NULL iklam@7089: } aoqi@0: if (stream != NULL) { aoqi@0: break; aoqi@0: } aoqi@0: e = e->next(); aoqi@0: ++classpath_index; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (stream != NULL) { aoqi@0: // class file found, parse it aoqi@0: ClassFileParser parser(stream); aoqi@0: ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); aoqi@0: Handle protection_domain; aoqi@0: TempNewSymbol parsed_name = NULL; aoqi@0: instanceKlassHandle result = parser.parseClassFile(h_name, aoqi@0: loader_data, aoqi@0: protection_domain, aoqi@0: parsed_name, iklam@7089: context.should_verify(classpath_index), iklam@7089: THREAD); iklam@7089: if (HAS_PENDING_EXCEPTION) { iklam@7089: ResourceMark rm; iklam@7089: if (DumpSharedSpaces) { iklam@7089: tty->print_cr("Preload Error: Failed to load %s", class_name); iklam@7089: } iklam@7089: return h; iklam@7089: } iklam@7089: h = context.record_result(classpath_index, e, result, THREAD); iklam@7089: } else { iklam@7089: if (DumpSharedSpaces) { jiangli@7363: tty->print_cr("Preload Warning: Cannot find %s", class_name); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return h; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void ClassLoader::create_package_info_table(HashtableBucket *t, int length, aoqi@0: int number_of_entries) { aoqi@0: assert(_package_hash_table == NULL, "One package info table allowed."); aoqi@0: assert(length == package_hash_table_size * sizeof(HashtableBucket), aoqi@0: "bad shared package info size."); aoqi@0: _package_hash_table = new PackageHashtable(package_hash_table_size, t, aoqi@0: number_of_entries); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void ClassLoader::create_package_info_table() { aoqi@0: assert(_package_hash_table == NULL, "shouldn't have one yet"); aoqi@0: _package_hash_table = new PackageHashtable(package_hash_table_size); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Initialize the class loader's access to methods in libzip. Parse and aoqi@0: // process the boot classpath into a list ClassPathEntry objects. Once aoqi@0: // this list has been created, it must not change order (see class PackageInfo) aoqi@0: // it can be appended to and is by jvmti and the kernel vm. aoqi@0: aoqi@0: void ClassLoader::initialize() { aoqi@0: assert(_package_hash_table == NULL, "should have been initialized by now."); aoqi@0: EXCEPTION_MARK; aoqi@0: aoqi@0: if (UsePerfData) { aoqi@0: // jvmstat performance counters aoqi@0: NEWPERFTICKCOUNTER(_perf_accumulated_time, SUN_CLS, "time"); aoqi@0: NEWPERFTICKCOUNTER(_perf_class_init_time, SUN_CLS, "classInitTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_class_init_selftime, SUN_CLS, "classInitTime.self"); aoqi@0: NEWPERFTICKCOUNTER(_perf_class_verify_time, SUN_CLS, "classVerifyTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_class_verify_selftime, SUN_CLS, "classVerifyTime.self"); aoqi@0: NEWPERFTICKCOUNTER(_perf_class_link_time, SUN_CLS, "classLinkedTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_class_link_selftime, SUN_CLS, "classLinkedTime.self"); aoqi@0: NEWPERFEVENTCOUNTER(_perf_classes_inited, SUN_CLS, "initializedClasses"); aoqi@0: NEWPERFEVENTCOUNTER(_perf_classes_linked, SUN_CLS, "linkedClasses"); aoqi@0: NEWPERFEVENTCOUNTER(_perf_classes_verified, SUN_CLS, "verifiedClasses"); aoqi@0: aoqi@0: NEWPERFTICKCOUNTER(_perf_class_parse_time, SUN_CLS, "parseClassTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_class_parse_selftime, SUN_CLS, "parseClassTime.self"); aoqi@0: NEWPERFTICKCOUNTER(_perf_sys_class_lookup_time, SUN_CLS, "lookupSysClassTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_shared_classload_time, SUN_CLS, "sharedClassLoadTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_sys_classload_time, SUN_CLS, "sysClassLoadTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_app_classload_time, SUN_CLS, "appClassLoadTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_app_classload_selftime, SUN_CLS, "appClassLoadTime.self"); aoqi@0: NEWPERFEVENTCOUNTER(_perf_app_classload_count, SUN_CLS, "appClassLoadCount"); aoqi@0: NEWPERFTICKCOUNTER(_perf_define_appclasses, SUN_CLS, "defineAppClasses"); aoqi@0: NEWPERFTICKCOUNTER(_perf_define_appclass_time, SUN_CLS, "defineAppClassTime"); aoqi@0: NEWPERFTICKCOUNTER(_perf_define_appclass_selftime, SUN_CLS, "defineAppClassTime.self"); aoqi@0: NEWPERFBYTECOUNTER(_perf_app_classfile_bytes_read, SUN_CLS, "appClassBytes"); aoqi@0: NEWPERFBYTECOUNTER(_perf_sys_classfile_bytes_read, SUN_CLS, "sysClassBytes"); aoqi@0: aoqi@0: aoqi@0: // The following performance counters are added for measuring the impact aoqi@0: // of the bug fix of 6365597. They are mainly focused on finding out aoqi@0: // the behavior of system & user-defined classloader lock, whether aoqi@0: // ClassLoader.loadClass/findClass is being called synchronized or not. aoqi@0: // Also two additional counters are created to see whether 'UnsyncloadClass' aoqi@0: // flag is being set or not and how many times load_instance_class call aoqi@0: // fails with linkageError etc. aoqi@0: NEWPERFEVENTCOUNTER(_sync_systemLoaderLockContentionRate, SUN_CLS, aoqi@0: "systemLoaderLockContentionRate"); aoqi@0: NEWPERFEVENTCOUNTER(_sync_nonSystemLoaderLockContentionRate, SUN_CLS, aoqi@0: "nonSystemLoaderLockContentionRate"); aoqi@0: NEWPERFEVENTCOUNTER(_sync_JVMFindLoadedClassLockFreeCounter, SUN_CLS, aoqi@0: "jvmFindLoadedClassNoLockCalls"); aoqi@0: NEWPERFEVENTCOUNTER(_sync_JVMDefineClassLockFreeCounter, SUN_CLS, aoqi@0: "jvmDefineClassNoLockCalls"); aoqi@0: aoqi@0: NEWPERFEVENTCOUNTER(_sync_JNIDefineClassLockFreeCounter, SUN_CLS, aoqi@0: "jniDefineClassNoLockCalls"); aoqi@0: aoqi@0: NEWPERFEVENTCOUNTER(_unsafe_defineClassCallCounter, SUN_CLS, aoqi@0: "unsafeDefineClassCalls"); aoqi@0: aoqi@0: NEWPERFEVENTCOUNTER(_isUnsyncloadClass, SUN_CLS, "isUnsyncloadClassSet"); aoqi@0: NEWPERFEVENTCOUNTER(_load_instance_class_failCounter, SUN_CLS, aoqi@0: "loadInstanceClassFailRate"); aoqi@0: aoqi@0: // increment the isUnsyncloadClass counter if UnsyncloadClass is set. aoqi@0: if (UnsyncloadClass) { aoqi@0: _isUnsyncloadClass->inc(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // lookup zip library entry points aoqi@0: load_zip_library(); iklam@7089: #if INCLUDE_CDS aoqi@0: // initialize search path iklam@7089: if (DumpSharedSpaces) { iklam@7089: _shared_paths_misc_info = SharedClassUtil::allocate_shared_paths_misc_info(); iklam@7089: } iklam@7089: #endif aoqi@0: setup_bootstrap_search_path(); aoqi@0: if (LazyBootClassLoader) { aoqi@0: // set up meta index which makes boot classpath initialization lazier iklam@7089: setup_bootstrap_meta_index(); aoqi@0: } aoqi@0: } aoqi@0: iklam@7089: #if INCLUDE_CDS iklam@7089: void ClassLoader::initialize_shared_path() { iklam@7089: if (DumpSharedSpaces) { iklam@7089: ClassLoaderExt::setup_search_paths(); iklam@7089: _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check() iklam@7089: } iklam@7089: } iklam@7089: #endif aoqi@0: aoqi@0: jlong ClassLoader::classloader_time_ms() { aoqi@0: return UsePerfData ? aoqi@0: Management::ticks_to_ms(_perf_accumulated_time->get_value()) : -1; aoqi@0: } aoqi@0: aoqi@0: jlong ClassLoader::class_init_count() { aoqi@0: return UsePerfData ? _perf_classes_inited->get_value() : -1; aoqi@0: } aoqi@0: aoqi@0: jlong ClassLoader::class_init_time_ms() { aoqi@0: return UsePerfData ? aoqi@0: Management::ticks_to_ms(_perf_class_init_time->get_value()) : -1; aoqi@0: } aoqi@0: aoqi@0: jlong ClassLoader::class_verify_time_ms() { aoqi@0: return UsePerfData ? aoqi@0: Management::ticks_to_ms(_perf_class_verify_time->get_value()) : -1; aoqi@0: } aoqi@0: aoqi@0: jlong ClassLoader::class_link_count() { aoqi@0: return UsePerfData ? _perf_classes_linked->get_value() : -1; aoqi@0: } aoqi@0: aoqi@0: jlong ClassLoader::class_link_time_ms() { aoqi@0: return UsePerfData ? aoqi@0: Management::ticks_to_ms(_perf_class_link_time->get_value()) : -1; aoqi@0: } aoqi@0: aoqi@0: int ClassLoader::compute_Object_vtable() { aoqi@0: // hardwired for JDK1.2 -- would need to duplicate class file parsing aoqi@0: // code to determine actual value from file aoqi@0: // Would be value '11' if finals were in vtable aoqi@0: int JDK_1_2_Object_vtable_size = 5; aoqi@0: return JDK_1_2_Object_vtable_size * vtableEntry::size(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void classLoader_init() { aoqi@0: ClassLoader::initialize(); aoqi@0: } aoqi@0: aoqi@0: iklam@7090: bool ClassLoader::get_canonical_path(const char* orig, char* out, int len) { aoqi@0: assert(orig != NULL && out != NULL && len > 0, "bad arguments"); aoqi@0: if (CanonicalizeEntry != NULL) { iklam@7090: JavaThread* THREAD = JavaThread::current(); iklam@7090: JNIEnv* env = THREAD->jni_environment(); iklam@7090: ResourceMark rm(THREAD); iklam@7090: iklam@7090: // os::native_path writes into orig_copy iklam@7090: char* orig_copy = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(orig)+1); iklam@7090: strcpy(orig_copy, orig); iklam@7090: if ((CanonicalizeEntry)(env, os::native_path(orig_copy), out, len) < 0) { aoqi@0: return false; aoqi@0: } aoqi@0: } else { aoqi@0: // On JDK 1.2.2 the Canonicalize does not exist, so just do nothing aoqi@0: strncpy(out, orig, len); aoqi@0: out[len - 1] = '\0'; aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: #ifndef PRODUCT aoqi@0: aoqi@0: void ClassLoader::verify() { aoqi@0: _package_hash_table->verify(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // CompileTheWorld aoqi@0: // aoqi@0: // Iterates over all class path entries and forces compilation of all methods aoqi@0: // in all classes found. Currently, only zip/jar archives are searched. aoqi@0: // aoqi@0: // The classes are loaded by the Java level bootstrap class loader, and the aoqi@0: // initializer is called. If DelayCompilationDuringStartup is true (default), aoqi@0: // the interpreter will run the initialization code. Note that forcing aoqi@0: // initialization in this way could potentially lead to initialization order aoqi@0: // problems, in which case we could just force the initialization bit to be set. aoqi@0: aoqi@0: aoqi@0: // We need to iterate over the contents of a zip/jar file, so we replicate the aoqi@0: // jzcell and jzfile definitions from zip_util.h but rename jzfile to real_jzfile, aoqi@0: // since jzfile already has a void* definition. aoqi@0: // aoqi@0: // Note that this is only used in debug mode. aoqi@0: // aoqi@0: // HotSpot integration note: aoqi@0: // Matches zip_util.h 1.14 99/06/01 from jdk1.3 beta H build aoqi@0: aoqi@0: aoqi@0: // JDK 1.3 version aoqi@0: typedef struct real_jzentry13 { /* Zip file entry */ aoqi@0: char *name; /* entry name */ aoqi@0: jint time; /* modification time */ aoqi@0: jint size; /* size of uncompressed data */ aoqi@0: jint csize; /* size of compressed data (zero if uncompressed) */ aoqi@0: jint crc; /* crc of uncompressed data */ aoqi@0: char *comment; /* optional zip file comment */ aoqi@0: jbyte *extra; /* optional extra data */ aoqi@0: jint pos; /* position of LOC header (if negative) or data */ aoqi@0: } real_jzentry13; aoqi@0: aoqi@0: typedef struct real_jzfile13 { /* Zip file */ aoqi@0: char *name; /* zip file name */ aoqi@0: jint refs; /* number of active references */ aoqi@0: jint fd; /* open file descriptor */ aoqi@0: void *lock; /* read lock */ aoqi@0: char *comment; /* zip file comment */ aoqi@0: char *msg; /* zip error message */ aoqi@0: void *entries; /* array of hash cells */ aoqi@0: jint total; /* total number of entries */ aoqi@0: unsigned short *table; /* Hash chain heads: indexes into entries */ aoqi@0: jint tablelen; /* number of hash eads */ aoqi@0: real_jzfile13 *next; /* next zip file in search list */ aoqi@0: jzentry *cache; /* we cache the most recently freed jzentry */ aoqi@0: /* Information on metadata names in META-INF directory */ aoqi@0: char **metanames; /* array of meta names (may have null names) */ aoqi@0: jint metacount; /* number of slots in metanames array */ aoqi@0: /* If there are any per-entry comments, they are in the comments array */ aoqi@0: char **comments; aoqi@0: } real_jzfile13; aoqi@0: aoqi@0: // JDK 1.2 version aoqi@0: typedef struct real_jzentry12 { /* Zip file entry */ aoqi@0: char *name; /* entry name */ aoqi@0: jint time; /* modification time */ aoqi@0: jint size; /* size of uncompressed data */ aoqi@0: jint csize; /* size of compressed data (zero if uncompressed) */ aoqi@0: jint crc; /* crc of uncompressed data */ aoqi@0: char *comment; /* optional zip file comment */ aoqi@0: jbyte *extra; /* optional extra data */ aoqi@0: jint pos; /* position of LOC header (if negative) or data */ aoqi@0: struct real_jzentry12 *next; /* next entry in hash table */ aoqi@0: } real_jzentry12; aoqi@0: aoqi@0: typedef struct real_jzfile12 { /* Zip file */ aoqi@0: char *name; /* zip file name */ aoqi@0: jint refs; /* number of active references */ aoqi@0: jint fd; /* open file descriptor */ aoqi@0: void *lock; /* read lock */ aoqi@0: char *comment; /* zip file comment */ aoqi@0: char *msg; /* zip error message */ aoqi@0: real_jzentry12 *entries; /* array of zip entries */ aoqi@0: jint total; /* total number of entries */ aoqi@0: real_jzentry12 **table; /* hash table of entries */ aoqi@0: jint tablelen; /* number of buckets */ aoqi@0: jzfile *next; /* next zip file in search list */ aoqi@0: } real_jzfile12; aoqi@0: aoqi@0: aoqi@0: void ClassPathDirEntry::compile_the_world(Handle loader, TRAPS) { aoqi@0: // For now we only compile all methods in all classes in zip/jar files aoqi@0: tty->print_cr("CompileTheWorld : Skipped classes in %s", _dir); aoqi@0: tty->cr(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: bool ClassPathDirEntry::is_rt_jar() { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) { aoqi@0: if (JDK_Version::is_jdk12x_version()) { aoqi@0: compile_the_world12(loader, THREAD); aoqi@0: } else { aoqi@0: compile_the_world13(loader, THREAD); aoqi@0: } aoqi@0: if (HAS_PENDING_EXCEPTION) { aoqi@0: if (PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())) { aoqi@0: CLEAR_PENDING_EXCEPTION; aoqi@0: tty->print_cr("\nCompileTheWorld : Ran out of memory\n"); aoqi@0: tty->print_cr("Increase class metadata storage if a limit was set"); aoqi@0: } else { aoqi@0: tty->print_cr("\nCompileTheWorld : Unexpected exception occurred\n"); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // Version that works for JDK 1.3.x aoqi@0: void ClassPathZipEntry::compile_the_world13(Handle loader, TRAPS) { aoqi@0: real_jzfile13* zip = (real_jzfile13*) _zip; aoqi@0: tty->print_cr("CompileTheWorld : Compiling all classes in %s", zip->name); aoqi@0: tty->cr(); aoqi@0: // Iterate over all entries in zip file aoqi@0: for (int n = 0; ; n++) { aoqi@0: real_jzentry13 * ze = (real_jzentry13 *)((*GetNextEntry)(_zip, n)); aoqi@0: if (ze == NULL) break; aoqi@0: ClassLoader::compile_the_world_in(ze->name, loader, CHECK); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // Version that works for JDK 1.2.x aoqi@0: void ClassPathZipEntry::compile_the_world12(Handle loader, TRAPS) { aoqi@0: real_jzfile12* zip = (real_jzfile12*) _zip; aoqi@0: tty->print_cr("CompileTheWorld : Compiling all classes in %s", zip->name); aoqi@0: tty->cr(); aoqi@0: // Iterate over all entries in zip file aoqi@0: for (int n = 0; ; n++) { aoqi@0: real_jzentry12 * ze = (real_jzentry12 *)((*GetNextEntry)(_zip, n)); aoqi@0: if (ze == NULL) break; aoqi@0: ClassLoader::compile_the_world_in(ze->name, loader, CHECK); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool ClassPathZipEntry::is_rt_jar() { aoqi@0: if (JDK_Version::is_jdk12x_version()) { aoqi@0: return is_rt_jar12(); aoqi@0: } else { aoqi@0: return is_rt_jar13(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // JDK 1.3 version aoqi@0: bool ClassPathZipEntry::is_rt_jar13() { aoqi@0: real_jzfile13* zip = (real_jzfile13*) _zip; aoqi@0: int len = (int)strlen(zip->name); aoqi@0: // Check whether zip name ends in "rt.jar" aoqi@0: // This will match other archives named rt.jar as well, but this is aoqi@0: // only used for debugging. aoqi@0: return (len >= 6) && (strcasecmp(zip->name + len - 6, "rt.jar") == 0); aoqi@0: } aoqi@0: aoqi@0: // JDK 1.2 version aoqi@0: bool ClassPathZipEntry::is_rt_jar12() { aoqi@0: real_jzfile12* zip = (real_jzfile12*) _zip; aoqi@0: int len = (int)strlen(zip->name); aoqi@0: // Check whether zip name ends in "rt.jar" aoqi@0: // This will match other archives named rt.jar as well, but this is aoqi@0: // only used for debugging. aoqi@0: return (len >= 6) && (strcasecmp(zip->name + len - 6, "rt.jar") == 0); aoqi@0: } aoqi@0: aoqi@0: void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) { aoqi@0: ClassPathEntry* cpe = resolve_entry(THREAD); aoqi@0: if (cpe != NULL) { aoqi@0: cpe->compile_the_world(loader, CHECK); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool LazyClassPathEntry::is_rt_jar() { aoqi@0: Thread* THREAD = Thread::current(); aoqi@0: ClassPathEntry* cpe = resolve_entry(THREAD); aoqi@0: return (cpe != NULL) ? cpe->is_jar_file() : false; aoqi@0: } aoqi@0: aoqi@0: void ClassLoader::compile_the_world() { aoqi@0: EXCEPTION_MARK; aoqi@0: HandleMark hm(THREAD); aoqi@0: ResourceMark rm(THREAD); aoqi@0: // Make sure we don't run with background compilation aoqi@0: BackgroundCompilation = false; aoqi@0: // Find bootstrap loader aoqi@0: Handle system_class_loader (THREAD, SystemDictionary::java_system_loader()); aoqi@0: // Iterate over all bootstrap class path entries aoqi@0: ClassPathEntry* e = _first_entry; aoqi@0: jlong start = os::javaTimeMillis(); aoqi@0: while (e != NULL) { aoqi@0: // We stop at rt.jar, unless it is the first bootstrap path entry aoqi@0: if (e->is_rt_jar() && e != _first_entry) break; aoqi@0: e->compile_the_world(system_class_loader, CATCH); aoqi@0: e = e->next(); aoqi@0: } aoqi@0: jlong end = os::javaTimeMillis(); aoqi@0: tty->print_cr("CompileTheWorld : Done (%d classes, %d methods, " JLONG_FORMAT " ms)", aoqi@0: _compile_the_world_class_counter, _compile_the_world_method_counter, (end - start)); aoqi@0: { aoqi@0: // Print statistics as if before normal exit: aoqi@0: extern void print_statistics(); aoqi@0: print_statistics(); aoqi@0: } aoqi@0: vm_exit(0); aoqi@0: } aoqi@0: aoqi@0: int ClassLoader::_compile_the_world_class_counter = 0; aoqi@0: int ClassLoader::_compile_the_world_method_counter = 0; aoqi@0: static int _codecache_sweep_counter = 0; aoqi@0: aoqi@0: // Filter out all exceptions except OOMs aoqi@0: static void clear_pending_exception_if_not_oom(TRAPS) { aoqi@0: if (HAS_PENDING_EXCEPTION && aoqi@0: !PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())) { aoqi@0: CLEAR_PENDING_EXCEPTION; aoqi@0: } aoqi@0: // The CHECK at the caller will propagate the exception out aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns if the given method should be compiled when doing compile-the-world. aoqi@0: * aoqi@0: * TODO: This should be a private method in a CompileTheWorld class. aoqi@0: */ aoqi@0: static bool can_be_compiled(methodHandle m, int comp_level) { aoqi@0: assert(CompileTheWorld, "must be"); aoqi@0: aoqi@0: // It's not valid to compile a native wrapper for MethodHandle methods aoqi@0: // that take a MemberName appendix since the bytecode signature is not aoqi@0: // correct. aoqi@0: vmIntrinsics::ID iid = m->intrinsic_id(); aoqi@0: if (MethodHandles::is_signature_polymorphic(iid) && MethodHandles::has_member_arg(iid)) { aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: return CompilationPolicy::can_be_compiled(m, comp_level); aoqi@0: } aoqi@0: aoqi@0: void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) { aoqi@0: int len = (int)strlen(name); aoqi@0: if (len > 6 && strcmp(".class", name + len - 6) == 0) { aoqi@0: // We have a .class file aoqi@0: char buffer[2048]; aoqi@0: strncpy(buffer, name, len - 6); aoqi@0: buffer[len-6] = 0; aoqi@0: // If the file has a period after removing .class, it's not really a aoqi@0: // valid class file. The class loader will check everything else. aoqi@0: if (strchr(buffer, '.') == NULL) { aoqi@0: _compile_the_world_class_counter++; aoqi@0: if (_compile_the_world_class_counter > CompileTheWorldStopAt) return; aoqi@0: aoqi@0: // Construct name without extension aoqi@0: TempNewSymbol sym = SymbolTable::new_symbol(buffer, CHECK); aoqi@0: // Use loader to load and initialize class aoqi@0: Klass* ik = SystemDictionary::resolve_or_null(sym, loader, Handle(), THREAD); aoqi@0: instanceKlassHandle k (THREAD, ik); aoqi@0: if (k.not_null() && !HAS_PENDING_EXCEPTION) { aoqi@0: k->initialize(THREAD); aoqi@0: } aoqi@0: bool exception_occurred = HAS_PENDING_EXCEPTION; aoqi@0: clear_pending_exception_if_not_oom(CHECK); aoqi@0: if (CompileTheWorldPreloadClasses && k.not_null()) { aoqi@0: ConstantPool::preload_and_initialize_all_classes(k->constants(), THREAD); aoqi@0: if (HAS_PENDING_EXCEPTION) { aoqi@0: // If something went wrong in preloading we just ignore it aoqi@0: clear_pending_exception_if_not_oom(CHECK); aoqi@0: tty->print_cr("Preloading failed for (%d) %s", _compile_the_world_class_counter, buffer); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (_compile_the_world_class_counter >= CompileTheWorldStartAt) { aoqi@0: if (k.is_null() || exception_occurred) { aoqi@0: // If something went wrong (e.g. ExceptionInInitializerError) we skip this class aoqi@0: tty->print_cr("CompileTheWorld (%d) : Skipping %s", _compile_the_world_class_counter, buffer); aoqi@0: } else { aoqi@0: tty->print_cr("CompileTheWorld (%d) : %s", _compile_the_world_class_counter, buffer); aoqi@0: // Preload all classes to get around uncommon traps aoqi@0: // Iterate over all methods in class aoqi@0: int comp_level = CompilationPolicy::policy()->initial_compile_level(); aoqi@0: for (int n = 0; n < k->methods()->length(); n++) { aoqi@0: methodHandle m (THREAD, k->methods()->at(n)); aoqi@0: if (can_be_compiled(m, comp_level)) { aoqi@0: if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) { aoqi@0: // Give sweeper a chance to keep up with CTW aoqi@0: VM_ForceSafepoint op; aoqi@0: VMThread::execute(&op); aoqi@0: _codecache_sweep_counter = 0; aoqi@0: } aoqi@0: // Force compilation aoqi@0: CompileBroker::compile_method(m, InvocationEntryBci, comp_level, aoqi@0: methodHandle(), 0, "CTW", THREAD); aoqi@0: if (HAS_PENDING_EXCEPTION) { aoqi@0: clear_pending_exception_if_not_oom(CHECK); aoqi@0: tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string()); aoqi@0: } else { aoqi@0: _compile_the_world_method_counter++; aoqi@0: } aoqi@0: if (TieredCompilation && TieredStopAtLevel >= CompLevel_full_optimization) { aoqi@0: // Clobber the first compile and force second tier compilation aoqi@0: nmethod* nm = m->code(); iveresov@7147: if (nm != NULL && !m->is_method_handle_intrinsic()) { aoqi@0: // Throw out the code so that the code cache doesn't fill up aoqi@0: nm->make_not_entrant(); aoqi@0: m->clear_code(); aoqi@0: } aoqi@0: CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_full_optimization, aoqi@0: methodHandle(), 0, "CTW", THREAD); aoqi@0: if (HAS_PENDING_EXCEPTION) { aoqi@0: clear_pending_exception_if_not_oom(CHECK); aoqi@0: tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string()); aoqi@0: } else { aoqi@0: _compile_the_world_method_counter++; aoqi@0: } aoqi@0: } aoqi@0: } else { aoqi@0: tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string()); aoqi@0: } aoqi@0: aoqi@0: nmethod* nm = m->code(); iveresov@7147: if (nm != NULL && !m->is_method_handle_intrinsic()) { aoqi@0: // Throw out the code so that the code cache doesn't fill up aoqi@0: nm->make_not_entrant(); aoqi@0: m->clear_code(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: #endif //PRODUCT aoqi@0: aoqi@0: // Please keep following two functions at end of this file. With them placed at top or in middle of the file, aoqi@0: // they could get inlined by agressive compiler, an unknown trick, see bug 6966589. aoqi@0: void PerfClassTraceTime::initialize() { aoqi@0: if (!UsePerfData) return; aoqi@0: aoqi@0: if (_eventp != NULL) { aoqi@0: // increment the event counter aoqi@0: _eventp->inc(); aoqi@0: } aoqi@0: aoqi@0: // stop the current active thread-local timer to measure inclusive time aoqi@0: _prev_active_event = -1; aoqi@0: for (int i=0; i < EVENT_TYPE_COUNT; i++) { aoqi@0: if (_timers[i].is_active()) { aoqi@0: assert(_prev_active_event == -1, "should have only one active timer"); aoqi@0: _prev_active_event = i; aoqi@0: _timers[i].stop(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (_recursion_counters == NULL || (_recursion_counters[_event_type])++ == 0) { aoqi@0: // start the inclusive timer if not recursively called aoqi@0: _t.start(); aoqi@0: } aoqi@0: aoqi@0: // start thread-local timer of the given event type aoqi@0: if (!_timers[_event_type].is_active()) { aoqi@0: _timers[_event_type].start(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: PerfClassTraceTime::~PerfClassTraceTime() { aoqi@0: if (!UsePerfData) return; aoqi@0: aoqi@0: // stop the thread-local timer as the event completes aoqi@0: // and resume the thread-local timer of the event next on the stack aoqi@0: _timers[_event_type].stop(); aoqi@0: jlong selftime = _timers[_event_type].ticks(); aoqi@0: aoqi@0: if (_prev_active_event >= 0) { aoqi@0: _timers[_prev_active_event].start(); aoqi@0: } aoqi@0: aoqi@0: if (_recursion_counters != NULL && --(_recursion_counters[_event_type]) > 0) return; aoqi@0: aoqi@0: // increment the counters only on the leaf call aoqi@0: _t.stop(); aoqi@0: _timep->inc(_t.ticks()); aoqi@0: if (_selftimep != NULL) { aoqi@0: _selftimep->inc(selftime); aoqi@0: } aoqi@0: // add all class loading related event selftime to the accumulated time counter aoqi@0: ClassLoader::perf_accumulated_time()->inc(selftime); aoqi@0: aoqi@0: // reset the timer aoqi@0: _timers[_event_type].reset(); aoqi@0: }