提交 1b2cc6ab 编写于 作者: I iklam

8046070: Class Data Sharing clean up and refactoring

Summary: Cleaned up CDS to be more configurable, maintainable and extensible
Reviewed-by: dholmes, coleenp, acorn, mchung
上级 df845d7b
......@@ -70,7 +70,8 @@ ifeq ($(INCLUDE_CDS), false)
CXXFLAGS += -DINCLUDE_CDS=0
CFLAGS += -DINCLUDE_CDS=0
Src_Files_EXCLUDE += filemap.cpp metaspaceShared.cpp
Src_Files_EXCLUDE += filemap.cpp metaspaceShared*.cpp sharedPathsMiscInfo.cpp \
systemDictionaryShared.cpp classLoaderExt.cpp sharedClassUtil.cpp
endif
ifeq ($(INCLUDE_ALL_GCS), false)
......
......@@ -2244,7 +2244,7 @@ void os::print_siginfo(outputStream* st, void* siginfo) {
const siginfo_t* si = (const siginfo_t*)siginfo;
os::Posix::print_siginfo_brief(st, si);
#if INCLUDE_CDS
if (si && (si->si_signo == SIGBUS || si->si_signo == SIGSEGV) &&
UseSharedSpaces) {
FileMapInfo* mapinfo = FileMapInfo::current_info();
......@@ -2254,6 +2254,7 @@ void os::print_siginfo(outputStream* st, void* siginfo) {
" possible disk/network problem.");
}
}
#endif
st->cr();
}
......
......@@ -31,6 +31,9 @@
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#if INCLUDE_CDS
#include "classfile/systemDictionaryShared.hpp"
#endif
#include "classfile/verificationType.hpp"
#include "classfile/verifier.hpp"
#include "classfile/vmSymbols.hpp"
......@@ -60,6 +63,7 @@
#include "services/threadService.hpp"
#include "utilities/array.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
// We generally try to create the oops directly when parsing, rather than
// allocating temporary data structures and copying the bytes twice. A
......@@ -3737,7 +3741,15 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
instanceKlassHandle nullHandle;
// Figure out whether we can skip format checking (matching classic VM behavior)
_need_verify = Verifier::should_verify_for(class_loader(), verify);
if (DumpSharedSpaces) {
// verify == true means it's a 'remote' class (i.e., non-boot class)
// Verification decision is based on BytecodeVerificationRemote flag
// for those classes.
_need_verify = (verify) ? BytecodeVerificationRemote :
BytecodeVerificationLocal;
} else {
_need_verify = Verifier::should_verify_for(class_loader(), verify);
}
// Set the verify flag in stream
cfs->set_verify(_need_verify);
......@@ -3756,6 +3768,18 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
u2 minor_version = cfs->get_u2_fast();
u2 major_version = cfs->get_u2_fast();
if (DumpSharedSpaces && major_version < JAVA_1_5_VERSION) {
ResourceMark rm;
warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s",
major_version, minor_version, name->as_C_string());
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_UnsupportedClassVersionError(),
"Unsupported major.minor version for dump time %u.%u",
major_version,
minor_version);
}
// Check version numbers - we check this even with verifier off
if (!is_supported_version(major_version, minor_version)) {
if (name == NULL) {
......@@ -3863,6 +3887,18 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
if (cfs->source() != NULL) tty->print(" from %s", cfs->source());
tty->print_cr("]");
}
#if INCLUDE_CDS
if (DumpLoadedClassList != NULL && cfs->source() != NULL && classlist_file->is_open()) {
// Only dump the classes that can be stored into CDS archive
if (SystemDictionaryShared::is_sharing_possible(loader_data)) {
if (name != NULL) {
ResourceMark rm(THREAD);
classlist_file->print_cr("%s", name->as_C_string());
classlist_file->flush();
}
}
}
#endif
u2 super_class_index = cfs->get_u2_fast();
instanceKlassHandle super_klass = parse_super_class(super_class_index,
......
......@@ -107,6 +107,7 @@ class ClassPathZipEntry: public ClassPathEntry {
const char* name() { return _zip_name; }
ClassPathZipEntry(jzfile* zip, const char* zip_name);
~ClassPathZipEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
ClassFileStream* open_stream(const char* name, TRAPS);
void contents_do(void f(const char* name, void* context), void* context);
// Debugging
......@@ -126,12 +127,14 @@ class LazyClassPathEntry: public ClassPathEntry {
struct stat _st;
MetaIndex* _meta_index;
bool _has_error;
bool _throw_exception;
volatile ClassPathEntry* _resolved_entry;
ClassPathEntry* resolve_entry(TRAPS);
public:
bool is_jar_file();
const char* name() { return _path; }
LazyClassPathEntry(char* path, const struct stat* st);
LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception);
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
ClassFileStream* open_stream(const char* name, TRAPS);
void set_meta_index(MetaIndex* meta_index) { _meta_index = meta_index; }
virtual bool is_lazy();
......@@ -142,6 +145,7 @@ class LazyClassPathEntry: public ClassPathEntry {
class PackageHashtable;
class PackageInfo;
class SharedPathsMiscInfo;
template <MEMFLAGS F> class HashtableBucket;
class ClassLoader: AllStatic {
......@@ -149,7 +153,7 @@ class ClassLoader: AllStatic {
enum SomeConstants {
package_hash_table_size = 31 // Number of buckets
};
private:
protected:
friend class LazyClassPathEntry;
// Performance counters
......@@ -191,10 +195,15 @@ class ClassLoader: AllStatic {
static ClassPathEntry* _first_entry;
// Last entry in linked list of ClassPathEntry instances
static ClassPathEntry* _last_entry;
static int _num_entries;
// Hash table used to keep track of loaded packages
static PackageHashtable* _package_hash_table;
static const char* _shared_archive;
// Info used by CDS
CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;)
// Hash function
static unsigned int hash(const char *s, int n);
// Returns the package file name corresponding to the specified package
......@@ -205,19 +214,23 @@ class ClassLoader: AllStatic {
static bool add_package(const char *pkgname, int classpath_index, TRAPS);
// Initialization
static void setup_meta_index();
static void setup_bootstrap_meta_index();
static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir,
int start_index);
static void setup_bootstrap_search_path();
static void setup_search_path(char *class_path);
static void load_zip_library();
static ClassPathEntry* create_class_path_entry(char *path, const struct stat* st,
bool lazy, TRAPS);
bool lazy, bool throw_exception, TRAPS);
// Canonicalizes path names, so strcmp will work properly. This is mainly
// to avoid confusing the zip library
static bool get_canonical_path(char* orig, char* out, int len);
public:
// Used by the kernel jvm.
static void update_class_path_entry_list(char *path,
bool check_for_duplicates);
static bool update_class_path_entry_list(char *path,
bool check_for_duplicates,
bool throw_exception=true);
static void print_bootclasspath();
// Timing
......@@ -300,6 +313,7 @@ class ClassLoader: AllStatic {
// Initialization
static void initialize();
CDS_ONLY(static void initialize_shared_path();)
static void create_package_info_table();
static void create_package_info_table(HashtableBucket<mtClass> *t, int length,
int number_of_entries);
......@@ -314,10 +328,21 @@ class ClassLoader: AllStatic {
return e;
}
#if INCLUDE_CDS
// Sharing dump and restore
static void copy_package_info_buckets(char** top, char* end);
static void copy_package_info_table(char** top, char* end);
static void check_shared_classpath(const char *path);
static void finalize_shared_paths_misc_info();
static int get_shared_paths_misc_info_size();
static void* get_shared_paths_misc_info();
static bool check_shared_paths_misc_info(void* info, int size);
static void exit_with_path_failure(const char* error, const char* message);
#endif
static void trace_class_path(const char* msg, const char* name = NULL);
// VM monitoring and management support
static jlong classloader_time_ms();
static jlong class_method_total_size();
......@@ -341,7 +366,7 @@ class ClassLoader: AllStatic {
// Force compilation of all methods in all classes in bootstrap class path (stress test)
#ifndef PRODUCT
private:
protected:
static int _compile_the_world_class_counter;
static int _compile_the_world_method_counter;
public:
......
/*
* 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_CLASSLOADEREXT_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
#include "classfile/classLoader.hpp"
class ClassLoaderExt: public ClassLoader { // AllStatic
public:
class Context {
const char* _file_name;
public:
Context(const char* class_name, const char* file_name, TRAPS) {
_file_name = file_name;
}
bool check(ClassFileStream* stream, const int classpath_index) {
return true;
}
bool should_verify(int classpath_index) {
return false;
}
instanceKlassHandle record_result(const int classpath_index,
ClassPathEntry* e, instanceKlassHandle result, TRAPS) {
if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
if (DumpSharedSpaces) {
result->set_shared_classpath_index(classpath_index);
}
return result;
} else {
return instanceKlassHandle(); // NULL
}
}
};
static void add_class_path_entry(char* path, bool check_for_duplicates,
ClassPathEntry* new_entry) {
ClassLoader::add_to_list(new_entry);
}
static void setup_search_paths() {}
};
#endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
......@@ -209,6 +209,29 @@ void Dictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
_pd_cache_table->roots_oops_do(strong, weak);
}
void Dictionary::remove_classes_in_error_state() {
assert(DumpSharedSpaces, "supported only when dumping");
DictionaryEntry* probe = NULL;
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry** p = bucket_addr(index); *p != NULL; ) {
probe = *p;
InstanceKlass* ik = InstanceKlass::cast(probe->klass());
if (ik->is_in_error_state()) { // purge this entry
*p = probe->next();
if (probe == _current_class_entry) {
_current_class_entry = NULL;
}
free_entry(probe);
ResourceMark rm;
tty->print_cr("Removed error class: %s", ik->external_name());
continue;
}
p = probe->next_addr();
}
}
}
void Dictionary::always_strong_oops_do(OopClosure* blk) {
// Follow all system classes and temporary placeholders in dictionary; only
// protection domain oops contain references into the heap. In a first
......@@ -682,16 +705,17 @@ void SymbolPropertyTable::methods_do(void f(Method*)) {
// ----------------------------------------------------------------------------
#ifndef PRODUCT
void Dictionary::print() {
void Dictionary::print(bool details) {
ResourceMark rm;
HandleMark hm;
tty->print_cr("Java system dictionary (table_size=%d, classes=%d)",
table_size(), number_of_entries());
tty->print_cr("^ indicates that initiating loader is different from "
"defining loader");
if (details) {
tty->print_cr("Java system dictionary (table_size=%d, classes=%d)",
table_size(), number_of_entries());
tty->print_cr("^ indicates that initiating loader is different from "
"defining loader");
}
for (int index = 0; index < table_size(); index++) {
for (DictionaryEntry* probe = bucket(index);
......@@ -702,21 +726,28 @@ void Dictionary::print() {
ClassLoaderData* loader_data = probe->loader_data();
bool is_defining_class =
(loader_data == InstanceKlass::cast(e)->class_loader_data());
tty->print("%s%s", is_defining_class ? " " : "^",
tty->print("%s%s", ((!details) || is_defining_class) ? " " : "^",
e->external_name());
if (details) {
tty->print(", loader ");
loader_data->print_value();
if (loader_data != NULL) {
loader_data->print_value();
} else {
tty->print("NULL");
}
}
tty->cr();
}
}
tty->cr();
_pd_cache_table->print();
if (details) {
tty->cr();
_pd_cache_table->print();
}
tty->cr();
}
#endif
void Dictionary::verify() {
guarantee(number_of_entries() >= 0, "Verify of system dictionary failed");
......
......@@ -100,6 +100,7 @@ public:
void methods_do(void f(Method*));
void unlink(BoolObjectClosure* is_alive);
void remove_classes_in_error_state();
// Classes loaded by the bootstrap loader are always strongly reachable.
// If we're not doing class unloading, all classes are strongly reachable.
......@@ -126,9 +127,7 @@ public:
ProtectionDomainCacheEntry* cache_get(oop protection_domain);
#ifndef PRODUCT
void print();
#endif
void print(bool details = true);
void verify();
};
......
/*
* 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_SHAREDCLASSUTIL_HPP
#define SHARE_VM_CLASSFILE_SHAREDCLASSUTIL_HPP
#include "classfile/sharedPathsMiscInfo.hpp"
#include "memory/filemap.hpp"
class SharedClassUtil : AllStatic {
public:
static SharedPathsMiscInfo* allocate_shared_paths_misc_info() {
return new SharedPathsMiscInfo();
}
static SharedPathsMiscInfo* allocate_shared_paths_misc_info(char* buf, int size) {
return new SharedPathsMiscInfo(buf, size);
}
static FileMapInfo::FileMapHeader* allocate_file_map_header() {
return new FileMapInfo::FileMapHeader();
}
static size_t file_map_header_size() {
return sizeof(FileMapInfo::FileMapHeader);
}
static size_t shared_class_path_entry_size() {
return sizeof(SharedClassPathEntry);
}
static void update_shared_classpath(ClassPathEntry *cpe,
SharedClassPathEntry* ent,
time_t timestamp,
long filesize, TRAPS) {
ent->_timestamp = timestamp;
ent->_filesize = filesize;
}
static void initialize(TRAPS) {}
inline static bool is_shared_boot_class(Klass* klass) {
return (klass->_shared_class_path_index >= 0);
}
};
#endif // SHARE_VM_CLASSFILE_SHAREDCLASSUTIL_HPP
/*
* 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/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/sharedPathsMiscInfo.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/metaspaceShared.hpp"
#include "runtime/arguments.hpp"
void SharedPathsMiscInfo::add_path(const char* path, int type) {
if (TraceClassPaths) {
tty->print("[type=%s] ", type_name(type));
trace_class_path("[Add misc shared path ", path);
}
write(path, strlen(path) + 1);
write_jint(jint(type));
}
void SharedPathsMiscInfo::ensure_size(size_t needed_bytes) {
assert(_allocated, "cannot modify buffer during validation.");
int used = get_used_bytes();
int target = used + int(needed_bytes);
if (target > _buf_size) {
_buf_size = _buf_size * 2 + (int)needed_bytes;
_buf_start = REALLOC_C_HEAP_ARRAY(char, _buf_start, _buf_size, mtClass);
_cur_ptr = _buf_start + used;
_end_ptr = _buf_start + _buf_size;
}
}
void SharedPathsMiscInfo::write(const void* ptr, size_t size) {
ensure_size(size);
memcpy(_cur_ptr, ptr, size);
_cur_ptr += size;
}
bool SharedPathsMiscInfo::read(void* ptr, size_t size) {
if (_cur_ptr + size <= _end_ptr) {
memcpy(ptr, _cur_ptr, size);
_cur_ptr += size;
return true;
}
return false;
}
bool SharedPathsMiscInfo::fail(const char* msg, const char* name) {
ClassLoader::trace_class_path(msg, name);
MetaspaceShared::set_archive_loading_failed();
return false;
}
bool SharedPathsMiscInfo::check() {
// The whole buffer must be 0 terminated so that we can use strlen and strcmp
// without fear.
_end_ptr -= sizeof(jint);
if (_cur_ptr >= _end_ptr) {
return fail("Truncated archive file header");
}
if (*_end_ptr != 0) {
return fail("Corrupted archive file header");
}
while (_cur_ptr < _end_ptr) {
jint type;
const char* path = _cur_ptr;
_cur_ptr += strlen(path) + 1;
if (!read_jint(&type)) {
return fail("Corrupted archive file header");
}
if (TraceClassPaths) {
tty->print("[type=%s ", type_name(type));
print_path(tty, type, path);
tty->print_cr("]");
}
if (!check(type, path)) {
if (!PrintSharedArchiveAndExit) {
return false;
}
} else {
trace_class_path("[ok");
}
}
return true;
}
bool SharedPathsMiscInfo::check(jint type, const char* path) {
switch (type) {
case BOOT:
if (strcmp(path, Arguments::get_sysclasspath()) != 0) {
return fail("[BOOT classpath mismatch, actual: -Dsun.boot.class.path=", Arguments::get_sysclasspath());
}
break;
case NON_EXIST: // fall-through
case REQUIRED:
{
struct stat st;
if (os::stat(path, &st) != 0) {
// The file does not actually exist
if (type == REQUIRED) {
// but we require it to exist -> fail
return fail("Required file doesn't exist");
}
} else {
// The file actually exists
if (type == NON_EXIST) {
// But we want it to not exist -> fail
return fail("File must not exist");
}
time_t timestamp;
long filesize;
if (!read_time(&timestamp) || !read_long(&filesize)) {
return fail("Corrupted archive file header");
}
if (timestamp != st.st_mtime) {
return fail("Timestamp mismatch");
}
if (filesize != st.st_size) {
return fail("File size mismatch");
}
}
}
break;
default:
return fail("Corrupted archive file header");
}
return true;
}
/*
* 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_SHAREDPATHSMISCINFO_HPP
#define SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP
#include "runtime/os.hpp"
// During dumping time, when processing class paths, we build up the dump-time
// classpath. The JAR files that exist are stored in the list ClassLoader::_first_entry.
// However, we need to store other "misc" information for run-time checking, such as
//
// + The values of Arguments::get_sysclasspath() used during dumping.
//
// + The meta-index file(s) used during dumping (incl modification time and size)
//
// + The class path elements specified during dumping but did not exist --
// these elements must also be specified at run time, and they also must not
// exist at run time.
//
// These misc items are stored in a linear buffer in SharedPathsMiscInfo.
// The storage format is stream oriented to minimize its size.
//
// When writing the information to the archive file, SharedPathsMiscInfo is stored in
// the archive file header. At run-time, this information is used only during initialization
// (accessed using read() instead of mmap()), and is deallocated afterwards to save space.
//
// The SharedPathsMiscInfo class is used for both creating the the information (during
// dumping time) and validation (at run time). Different constructors are used in the
// two situations. See below.
class SharedPathsMiscInfo : public CHeapObj<mtClass> {
protected:
char* _buf_start;
char* _cur_ptr;
char* _end_ptr;
int _buf_size;
bool _allocated; // was _buf_start allocated by me?
void ensure_size(size_t needed_bytes);
void add_path(const char* path, int type);
void write(const void* ptr, size_t size);
bool read(void* ptr, size_t size);
static void trace_class_path(const char* msg, const char* name = NULL) {
ClassLoader::trace_class_path(msg, name);
}
protected:
static bool fail(const char* msg, const char* name = NULL);
virtual bool check(jint type, const char* path);
public:
enum {
INITIAL_BUF_SIZE = 128
};
// This constructor is used when creating the misc information (during dump)
SharedPathsMiscInfo() {
_buf_size = INITIAL_BUF_SIZE;
_cur_ptr = _buf_start = NEW_C_HEAP_ARRAY(char, _buf_size, mtClass);
_allocated = true;
}
// This constructor is used when validating the misc info (during run time)
SharedPathsMiscInfo(char *buff, int size) {
_cur_ptr = _buf_start = buff;
_end_ptr = _buf_start + size;
_buf_size = size;
_allocated = false;
}
~SharedPathsMiscInfo() {
if (_allocated) {
FREE_C_HEAP_ARRAY(char, _buf_start, mtClass);
}
}
int get_used_bytes() {
return _cur_ptr - _buf_start;
}
void* buffer() {
return _buf_start;
}
// writing --
// The path must not exist at run-time
void add_nonexist_path(const char* path) {
add_path(path, NON_EXIST);
}
// The path must exist and have required size and modification time
void add_required_file(const char* path) {
add_path(path, REQUIRED);
struct stat st;
if (os::stat(path, &st) != 0) {
assert(0, "sanity");
ClassLoader::exit_with_path_failure("failed to os::stat(%s)", path); // should not happen
}
write_time(st.st_mtime);
write_long(st.st_size);
}
// The path must exist, and must contain exactly <num_entries> files/dirs
void add_boot_classpath(const char* path) {
add_path(path, BOOT);
}
int write_jint(jint num) {
write(&num, sizeof(num));
return 0;
}
void write_time(time_t t) {
write(&t, sizeof(t));
}
void write_long(long l) {
write(&l, sizeof(l));
}
bool dump_to_file(int fd) {
int n = get_used_bytes();
return (os::write(fd, _buf_start, n) == (size_t)n);
}
// reading --
enum {
BOOT = 1,
NON_EXIST = 2,
REQUIRED = 3
};
virtual const char* type_name(int type) {
switch (type) {
case BOOT: return "BOOT";
case NON_EXIST: return "NON_EXIST";
case REQUIRED: return "REQUIRED";
default: ShouldNotReachHere(); return "?";
}
}
virtual void print_path(outputStream* out, int type, const char* path) {
switch (type) {
case BOOT:
out->print("Expecting -Dsun.boot.class.path=%s", path);
break;
case NON_EXIST:
out->print("Expecting that %s does not exist", path);
break;
case REQUIRED:
out->print("Expecting that file %s must exist and not altered", path);
break;
default:
ShouldNotReachHere();
}
}
bool check();
bool read_jint(jint *ptr) {
return read(ptr, sizeof(jint));
}
bool read_long(long *ptr) {
return read(ptr, sizeof(long));
}
bool read_time(time_t *ptr) {
return read(ptr, sizeof(time_t));
}
};
#endif // SHARE_VM_CLASSFILE_SHAREDPATHSMISCINFO_HPP
......@@ -30,10 +30,15 @@
#include "classfile/placeholders.hpp"
#include "classfile/resolutionErrors.hpp"
#include "classfile/systemDictionary.hpp"
#if INCLUDE_CDS
#include "classfile/sharedClassUtil.hpp"
#include "classfile/systemDictionaryShared.hpp"
#endif
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/filemap.hpp"
#include "memory/gcLocker.hpp"
#include "memory/oopFactory.hpp"
#include "oops/instanceKlass.hpp"
......@@ -109,6 +114,8 @@ void SystemDictionary::compute_java_system_loader(TRAPS) {
CHECK);
_java_system_loader = (oop)result.get_jobject();
CDS_ONLY(SystemDictionaryShared::initialize(CHECK);)
}
......@@ -974,6 +981,7 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
// as the host_klass
assert(EnableInvokeDynamic, "");
guarantee(host_klass->class_loader() == class_loader(), "should be the same");
guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
loader_data->record_dependency(host_klass(), CHECK_NULL);
} else {
......@@ -1135,7 +1143,7 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
return k();
}
#if INCLUDE_CDS
void SystemDictionary::set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
int number_of_entries) {
assert(length == _nof_buckets * sizeof(HashtableBucket<mtClass>),
......@@ -1168,15 +1176,21 @@ Klass* SystemDictionary::find_shared_class(Symbol* class_name) {
instanceKlassHandle SystemDictionary::load_shared_class(
Symbol* class_name, Handle class_loader, TRAPS) {
instanceKlassHandle ik (THREAD, find_shared_class(class_name));
return load_shared_class(ik, class_loader, THREAD);
// Make sure we only return the boot class for the NULL classloader.
if (ik.not_null() &&
SharedClassUtil::is_shared_boot_class(ik()) && class_loader.is_null()) {
Handle protection_domain;
return load_shared_class(ik, class_loader, protection_domain, THREAD);
}
return instanceKlassHandle();
}
instanceKlassHandle SystemDictionary::load_shared_class(
instanceKlassHandle ik, Handle class_loader, TRAPS) {
assert(class_loader.is_null(), "non-null classloader for shared class?");
instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik,
Handle class_loader,
Handle protection_domain, TRAPS) {
if (ik.not_null()) {
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
Symbol* class_name = ik->name();
Symbol* class_name = ik->name();
// Found the class, now load the superclass and interfaces. If they
// are shared, add them to the main system dictionary and reset
......@@ -1185,7 +1199,7 @@ instanceKlassHandle SystemDictionary::load_shared_class(
if (ik->super() != NULL) {
Symbol* cn = ik->super()->name();
resolve_super_or_fail(class_name, cn,
class_loader, Handle(), true, CHECK_(nh));
class_loader, protection_domain, true, CHECK_(nh));
}
Array<Klass*>* interfaces = ik->local_interfaces();
......@@ -1198,7 +1212,7 @@ instanceKlassHandle SystemDictionary::load_shared_class(
// reinitialized yet (they will be once the interface classes
// are loaded)
Symbol* name = k->name();
resolve_super_or_fail(class_name, name, class_loader, Handle(), false, CHECK_(nh));
resolve_super_or_fail(class_name, name, class_loader, protection_domain, false, CHECK_(nh));
}
// Adjust methods to recover missing data. They need addresses for
......@@ -1207,30 +1221,47 @@ instanceKlassHandle SystemDictionary::load_shared_class(
// Updating methods must be done under a lock so multiple
// threads don't update these in parallel
// Shared classes are all currently loaded by the bootstrap
// classloader, so this will never cause a deadlock on
// a custom class loader lock.
//
// Shared classes are all currently loaded by either the bootstrap or
// internal parallel class loaders, so this will never cause a deadlock
// on a custom class loader lock.
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
{
Handle lockObject = compute_loader_lock_object(class_loader, THREAD);
check_loader_lock_contention(lockObject, THREAD);
ObjectLocker ol(lockObject, THREAD, true);
ik->restore_unshareable_info(CHECK_(nh));
ik->restore_unshareable_info(loader_data, protection_domain, CHECK_(nh));
}
if (TraceClassLoading) {
ResourceMark rm;
tty->print("[Loaded %s", ik->external_name());
tty->print(" from shared objects file");
if (class_loader.not_null()) {
tty->print(" by %s", loader_data->loader_name());
}
tty->print_cr("]");
}
#if INCLUDE_CDS
if (DumpLoadedClassList != NULL && classlist_file->is_open()) {
// Only dump the classes that can be stored into CDS archive
if (SystemDictionaryShared::is_sharing_possible(loader_data)) {
ResourceMark rm(THREAD);
classlist_file->print_cr("%s", ik->name()->as_C_string());
classlist_file->flush();
}
}
#endif
// notify a class loaded from shared object
ClassLoadingService::notify_class_loaded(InstanceKlass::cast(ik()),
true /* shared class */);
}
return ik;
}
#endif
instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
......@@ -1240,8 +1271,10 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha
// shared spaces.
instanceKlassHandle k;
{
#if INCLUDE_CDS
PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time());
k = load_shared_class(class_name, class_loader, THREAD);
#endif
}
if (k.is_null()) {
......@@ -1600,7 +1633,6 @@ void SystemDictionary::add_to_hierarchy(instanceKlassHandle k, TRAPS) {
Universe::flush_dependents_on(k);
}
// ----------------------------------------------------------------------------
// GC support
......@@ -1682,6 +1714,7 @@ bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) {
void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
strong->do_oop(&_java_system_loader);
strong->do_oop(&_system_loader_lock_obj);
CDS_ONLY(SystemDictionaryShared::roots_oops_do(strong);)
// Adjust dictionary
dictionary()->roots_oops_do(strong, weak);
......@@ -1693,6 +1726,7 @@ void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
void SystemDictionary::oops_do(OopClosure* f) {
f->do_oop(&_java_system_loader);
f->do_oop(&_system_loader_lock_obj);
CDS_ONLY(SystemDictionaryShared::oops_do(f);)
// Adjust dictionary
dictionary()->oops_do(f);
......@@ -1754,6 +1788,10 @@ void SystemDictionary::methods_do(void f(Method*)) {
invoke_method_table()->methods_do(f);
}
void SystemDictionary::remove_classes_in_error_state() {
dictionary()->remove_classes_in_error_state();
}
// ----------------------------------------------------------------------------
// Lazily load klasses
......@@ -2566,10 +2604,12 @@ int SystemDictionary::number_of_classes() {
// ----------------------------------------------------------------------------
#ifndef PRODUCT
void SystemDictionary::print_shared(bool details) {
shared_dictionary()->print(details);
}
void SystemDictionary::print() {
dictionary()->print();
void SystemDictionary::print(bool details) {
dictionary()->print(details);
// Placeholders
GCMutexLocker mu(SystemDictionary_lock);
......@@ -2579,7 +2619,6 @@ void SystemDictionary::print() {
constraints()->print();
}
#endif
void SystemDictionary::verify() {
guarantee(dictionary() != NULL, "Verify of system dictionary failed");
......
......@@ -111,6 +111,7 @@ class Ticks;
do_klass(SecurityManager_klass, java_lang_SecurityManager, Pre ) \
do_klass(ProtectionDomain_klass, java_security_ProtectionDomain, Pre ) \
do_klass(AccessControlContext_klass, java_security_AccessControlContext, Pre ) \
do_klass(SecureClassLoader_klass, java_security_SecureClassLoader, Pre ) \
do_klass(ClassNotFoundException_klass, java_lang_ClassNotFoundException, Pre ) \
do_klass(NoClassDefFoundError_klass, java_lang_NoClassDefFoundError, Pre ) \
do_klass(LinkageError_klass, java_lang_LinkageError, Pre ) \
......@@ -167,6 +168,15 @@ class Ticks;
do_klass(StringBuilder_klass, java_lang_StringBuilder, Pre ) \
do_klass(misc_Unsafe_klass, sun_misc_Unsafe, Pre ) \
\
/* support for CDS */ \
do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream, Pre ) \
do_klass(File_klass, java_io_File, Pre ) \
do_klass(URLClassLoader_klass, java_net_URLClassLoader, Pre ) \
do_klass(URL_klass, java_net_URL, Pre ) \
do_klass(Jar_Manifest_klass, java_util_jar_Manifest, Pre ) \
do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \
do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \
\
/* It's NULL in non-1.4 JDKs. */ \
do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \
/* Universe::is_gte_jdk14x_version() is not set up by this point. */ \
......@@ -226,7 +236,7 @@ class SystemDictionary : AllStatic {
static Klass* resolve_or_fail(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS);
// Convenient call for null loader and protection domain.
static Klass* resolve_or_fail(Symbol* class_name, bool throw_error, TRAPS);
private:
protected:
// handle error translation for resolve_or_null results
static Klass* handle_resolution_exception(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, KlassHandle klass_h, TRAPS);
......@@ -331,6 +341,9 @@ public:
// loaders. Returns "true" iff something was unloaded.
static bool do_unloading(BoolObjectClosure* is_alive);
// Used by DumpSharedSpaces only to remove classes that failed verification
static void remove_classes_in_error_state();
static int calculate_systemdictionary_size(int loadedclasses);
// Applies "f->do_oop" to all root oops in the system dictionary.
......@@ -340,7 +353,7 @@ public:
// System loader lock
static oop system_loader_lock() { return _system_loader_lock_obj; }
private:
protected:
// Extended Redefine classes support (tbi)
static void preloaded_classes_do(KlassClosure* f);
static void lazily_loaded_classes_do(KlassClosure* f);
......@@ -353,7 +366,8 @@ public:
static void set_shared_dictionary(HashtableBucket<mtClass>* t, int length,
int number_of_entries);
// Printing
static void print() PRODUCT_RETURN;
static void print(bool details = true);
static void print_shared(bool details = true);
static void print_class_statistics() PRODUCT_RETURN;
static void print_method_statistics() PRODUCT_RETURN;
......@@ -439,7 +453,7 @@ public:
static void load_abstract_ownable_synchronizer_klass(TRAPS);
private:
protected:
// Tells whether ClassLoader.loadClassInternal is present
static bool has_loadClassInternal() { return _has_loadClassInternal; }
......@@ -467,7 +481,7 @@ public:
// Register a new class loader
static ClassLoaderData* register_loader(Handle class_loader, TRAPS);
private:
protected:
// Mirrors for primitive classes (created eagerly)
static oop check_mirror(oop m) {
assert(m != NULL, "mirror not initialized");
......@@ -536,7 +550,7 @@ public:
static void delete_resolution_error(ConstantPool* pool);
static Symbol* find_resolution_error(constantPoolHandle pool, int which);
private:
protected:
enum Constants {
_loader_constraint_size = 107, // number of entries in constraint table
......@@ -587,7 +601,7 @@ public:
friend class CounterDecay;
static Klass* try_get_next_class();
private:
protected:
static void validate_protection_domain(instanceKlassHandle klass,
Handle class_loader,
Handle protection_domain, TRAPS);
......@@ -614,10 +628,10 @@ private:
static instanceKlassHandle find_or_define_instance_class(Symbol* class_name,
Handle class_loader,
instanceKlassHandle k, TRAPS);
static instanceKlassHandle load_shared_class(Symbol* class_name,
Handle class_loader, TRAPS);
static instanceKlassHandle load_shared_class(instanceKlassHandle ik,
Handle class_loader, TRAPS);
Handle class_loader,
Handle protection_domain,
TRAPS);
static instanceKlassHandle load_instance_class(Symbol* class_name, Handle class_loader, TRAPS);
static Handle compute_loader_lock_object(Handle class_loader, TRAPS);
static void check_loader_lock_contention(Handle loader_lock, TRAPS);
......@@ -625,9 +639,12 @@ private:
static bool is_parallelDefine(Handle class_loader);
public:
static instanceKlassHandle load_shared_class(Symbol* class_name,
Handle class_loader,
TRAPS);
static bool is_ext_class_loader(Handle class_loader);
private:
protected:
static Klass* find_shared_class(Symbol* class_name);
// Setup link to hierarchy
......
/*
* 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_SYSTEMDICTIONARYSHARED_HPP
#define SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
#include "classfile/systemDictionary.hpp"
class SystemDictionaryShared: public SystemDictionary {
public:
static void initialize(TRAPS) {}
static instanceKlassHandle find_or_load_shared_class(Symbol* class_name,
Handle class_loader,
TRAPS) {
return instanceKlassHandle();
}
static void roots_oops_do(OopClosure* blk) {}
static void oops_do(OopClosure* f) {}
static bool is_sharing_possible(ClassLoaderData* loader_data) {
oop class_loader = loader_data->class_loader();
return (class_loader == NULL);
}
};
#endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
......@@ -91,11 +91,17 @@
template(java_lang_CharSequence, "java/lang/CharSequence") \
template(java_lang_SecurityManager, "java/lang/SecurityManager") \
template(java_security_AccessControlContext, "java/security/AccessControlContext") \
template(java_security_CodeSource, "java/security/CodeSource") \
template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \
template(java_security_SecureClassLoader, "java/security/SecureClassLoader") \
template(java_net_URLClassLoader, "java/net/URLClassLoader") \
template(java_net_URL, "java/net/URL") \
template(java_util_jar_Manifest, "java/util/jar/Manifest") \
template(impliesCreateAccessControlContext_name, "impliesCreateAccessControlContext") \
template(java_io_OutputStream, "java/io/OutputStream") \
template(java_io_Reader, "java/io/Reader") \
template(java_io_BufferedReader, "java/io/BufferedReader") \
template(java_io_File, "java/io/File") \
template(java_io_FileInputStream, "java/io/FileInputStream") \
template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \
template(java_io_Serializable, "java/io/Serializable") \
......@@ -106,6 +112,7 @@
template(java_util_Hashtable, "java/util/Hashtable") \
template(java_lang_Compiler, "java/lang/Compiler") \
template(sun_misc_Signal, "sun/misc/Signal") \
template(sun_misc_Launcher, "sun/misc/Launcher") \
template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \
template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \
template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \
......@@ -397,6 +404,14 @@
template(signers_name, "signers_name") \
template(loader_data_name, "loader_data") \
template(dependencies_name, "dependencies") \
template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \
template(getFileURL_name, "getFileURL") \
template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \
template(definePackageInternal_name, "definePackageInternal") \
template(definePackageInternal_signature, "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)V") \
template(getProtectionDomain_name, "getProtectionDomain") \
template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \
template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \
\
/* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \
......
......@@ -265,7 +265,8 @@ class MetaspaceObj {
f(ConstantPool) \
f(ConstantPoolCache) \
f(Annotation) \
f(MethodCounters)
f(MethodCounters) \
f(Deallocated)
#define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type,
#define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name;
......
此差异已折叠。
......@@ -37,30 +37,55 @@
// misc data (block offset table, string table, symbols, dictionary, etc.)
// tag(666)
static const int JVM_SHARED_JARS_MAX = 128;
static const int JVM_SPACENAME_MAX = 128;
static const int JVM_IDENT_MAX = 256;
static const int JVM_ARCH_MAX = 12;
class Metaspace;
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
bool is_dir() {
return _filesize == -1;
}
};
class FileMapInfo : public CHeapObj<mtInternal> {
private:
friend class ManifestStream;
enum {
_invalid_version = -1,
_current_version = 1
_current_version = 2
};
bool _file_open;
int _fd;
long _file_offset;
private:
static SharedClassPathEntry* _classpath_entry_table;
static int _classpath_entry_table_size;
static size_t _classpath_entry_size;
static bool _validating_classpath_entry_table;
// FileMapHeader describes the shared space data in the file to be
// mapped. This structure gets written to a file. It is not a class, so
// that the compilers don't add any compiler-private data to it.
struct FileMapHeader {
public:
struct FileMapHeaderBase : public CHeapObj<mtClass> {
virtual bool validate() = 0;
virtual void populate(FileMapInfo* info, size_t alignment) = 0;
};
struct FileMapHeader : FileMapHeaderBase {
// Use data() and data_size() to memcopy to/from the FileMapHeader. We need to
// avoid read/writing the C++ vtable pointer.
static size_t data_size();
char* data() {
return ((char*)this) + sizeof(FileMapHeaderBase);
}
int _magic; // identify file type.
int _version; // (from enum, above.)
size_t _alignment; // how shared archive should be aligned
......@@ -78,44 +103,64 @@ private:
// The following fields are all sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
// invoked with.
char _arch[JVM_ARCH_MAX]; // architecture
char _jvm_ident[JVM_IDENT_MAX]; // identifier for jvm
int _num_jars; // Number of jars in bootclasspath
// Per jar file data: timestamp, size.
// The _paths_misc_info is a variable-size structure that records "miscellaneous"
// information during dumping. It is generated and validated by the
// SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp and sharedClassUtil.hpp for
// detailed description.
//
// The _paths_misc_info data is stored as a byte array in the archive file header,
// immediately after the _header field. This information is used only when
// checking the validity of the archive and is deallocated after the archive is loaded.
//
// Note that the _paths_misc_info does NOT include information for JAR files
// that existed during dump time. Their information is stored in _classpath_entry_table.
int _paths_misc_info_size;
// The following is a table of all the class path entries that were used
// during dumping. At run time, we require these files to exist and have the same
// size/modification time, or else the archive will refuse to load.
//
// All of these entries must be JAR files. The dumping process would fail if a non-empty
// directory was specified in the classpaths. If an empty directory was specified
// it is checked by the _paths_misc_info as described above.
//
// FIXME -- if JAR files in the tail of the list were specified but not used during dumping,
// they should be removed from this table, to save space and to avoid spurious
// loading failures during runtime.
int _classpath_entry_table_size;
size_t _classpath_entry_size;
SharedClassPathEntry* _classpath_entry_table;
virtual bool validate();
virtual void populate(FileMapInfo* info, size_t alignment);
};
FileMapHeader * _header;
struct {
time_t _timestamp; // jar timestamp.
long _filesize; // jar file size.
} _jar[JVM_SHARED_JARS_MAX];
} _header;
const char* _full_path;
char* _paths_misc_info;
static FileMapInfo* _current_info;
bool init_from_file(int fd);
void align_file_position();
bool validate_header_impl();
public:
FileMapInfo() {
_file_offset = 0;
_file_open = false;
_header._version = _invalid_version;
}
FileMapInfo();
~FileMapInfo();
static int current_version() { return _current_version; }
void populate_header(size_t alignment);
bool validate();
bool validate_header();
void invalidate();
int version() { return _header._version; }
size_t alignment() { return _header._alignment; }
size_t space_capacity(int i) { return _header._space[i]._capacity; }
char* region_base(int i) { return _header._space[i]._base; }
struct FileMapHeader* header() { return &_header; }
static void set_current_info(FileMapInfo* info) {
CDS_ONLY(_current_info = info;)
}
int version() { return _header->_version; }
size_t alignment() { return _header->_alignment; }
size_t space_capacity(int i) { return _header->_space[i]._capacity; }
char* region_base(int i) { return _header->_space[i]._base; }
struct FileMapHeader* header() { return _header; }
static FileMapInfo* current_info() {
CDS_ONLY(return _current_info;)
......@@ -146,7 +191,7 @@ public:
// Errors.
static void fail_stop(const char *msg, ...);
void fail_continue(const char *msg, ...);
static void fail_continue(const char *msg, ...);
// Return true if given address is in the mapped shared space.
bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false);
......@@ -160,6 +205,22 @@ public:
// Stop CDS sharing and unmap CDS regions.
static void stop_sharing_and_unmap(const char* msg);
static void allocate_classpath_entry_table();
bool validate_classpath_entry_table();
static SharedClassPathEntry* shared_classpath(int index) {
char* p = (char*)_classpath_entry_table;
p += _classpath_entry_size * index;
return (SharedClassPathEntry*)p;
}
static const char* shared_classpath_name(int index) {
return shared_classpath(index)->_name;
}
static int get_number_of_share_classpaths() {
return _classpath_entry_table_size;
}
};
#endif // SHARE_VM_MEMORY_FILEMAP_HPP
......@@ -79,6 +79,12 @@ class MetadataFactory : AllStatic {
// Deallocation method for metadata
template <class T>
static void free_metadata(ClassLoaderData* loader_data, T md) {
if (DumpSharedSpaces) {
// FIXME: the freeing code is buggy, especially when PrintSharedSpaces is enabled.
// Disable for now -- this means if you specify bad classes in your classlist you
// may have wasted space inside the archive.
return;
}
if (md != NULL) {
assert(loader_data != NULL, "shouldn't pass null");
int size = md->size();
......
......@@ -413,6 +413,7 @@ static bool should_commit_large_pages_when_reserving(size_t bytes) {
VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs(), _container_count(0) {
assert_is_size_aligned(bytes, Metaspace::reserve_alignment());
#if INCLUDE_CDS
// This allocates memory with mmap. For DumpSharedspaces, try to reserve
// configurable address, generally at the top of the Java heap so other
// memory addresses don't conflict.
......@@ -428,7 +429,9 @@ VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs(
_rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages);
}
MetaspaceShared::set_shared_rs(&_rs);
} else {
} else
#endif
{
bool large_pages = should_commit_large_pages_when_reserving(bytes);
_rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages);
......@@ -2937,11 +2940,14 @@ void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address
// between the lower base and higher address.
address lower_base;
address higher_address;
#if INCLUDE_CDS
if (UseSharedSpaces) {
higher_address = MAX2((address)(cds_base + FileMapInfo::shared_spaces_size()),
(address)(metaspace_base + compressed_class_space_size()));
lower_base = MIN2(metaspace_base, cds_base);
} else {
} else
#endif
{
higher_address = metaspace_base + compressed_class_space_size();
lower_base = metaspace_base;
......@@ -2962,6 +2968,7 @@ void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address
}
}
#if INCLUDE_CDS
// Return TRUE if the specified metaspace_base and cds_base are close enough
// to work with compressed klass pointers.
bool Metaspace::can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base) {
......@@ -2972,6 +2979,7 @@ bool Metaspace::can_use_cds_with_metaspace_addr(char* metaspace_base, address cd
(address)(metaspace_base + compressed_class_space_size()));
return ((uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax);
}
#endif
// Try to allocate the metaspace at the requested addr.
void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base) {
......@@ -2991,6 +2999,7 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a
large_pages,
requested_addr, 0);
if (!metaspace_rs.is_reserved()) {
#if INCLUDE_CDS
if (UseSharedSpaces) {
size_t increment = align_size_up(1*G, _reserve_alignment);
......@@ -3005,7 +3014,7 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a
_reserve_alignment, large_pages, addr, 0);
}
}
#endif
// If no successful allocation then try to allocate the space anywhere. If
// that fails then OOM doom. At this point we cannot try allocating the
// metaspace as if UseCompressedClassPointers is off because too much
......@@ -3024,12 +3033,13 @@ void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, a
// If we got here then the metaspace got allocated.
MemTracker::record_virtual_memory_type((address)metaspace_rs.base(), mtClass);
#if INCLUDE_CDS
// Verify that we can use shared spaces. Otherwise, turn off CDS.
if (UseSharedSpaces && !can_use_cds_with_metaspace_addr(metaspace_rs.base(), cds_base)) {
FileMapInfo::stop_sharing_and_unmap(
"Could not allocate metaspace at a compatible address");
}
#endif
set_narrow_klass_base_and_shift((address)metaspace_rs.base(),
UseSharedSpaces ? (address)cds_base : 0);
......@@ -3113,6 +3123,7 @@ void Metaspace::global_initialize() {
MetaspaceShared::set_max_alignment(max_alignment);
if (DumpSharedSpaces) {
#if INCLUDE_CDS
SharedReadOnlySize = align_size_up(SharedReadOnlySize, max_alignment);
SharedReadWriteSize = align_size_up(SharedReadWriteSize, max_alignment);
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment);
......@@ -3150,23 +3161,22 @@ void Metaspace::global_initialize() {
}
Universe::set_narrow_klass_shift(0);
#endif
#endif // _LP64
#endif // INCLUDE_CDS
} else {
#if INCLUDE_CDS
// If using shared space, open the file that contains the shared space
// and map in the memory before initializing the rest of metaspace (so
// the addresses don't conflict)
address cds_address = NULL;
if (UseSharedSpaces) {
FileMapInfo* mapinfo = new FileMapInfo();
memset(mapinfo, 0, sizeof(FileMapInfo));
// Open the shared archive file, read and validate the header. If
// initialization fails, shared spaces [UseSharedSpaces] are
// disabled and the file is closed.
// Map in spaces now also
if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
FileMapInfo::set_current_info(mapinfo);
cds_total = FileMapInfo::shared_spaces_size();
cds_address = (address)mapinfo->region_base(0);
} else {
......@@ -3174,21 +3184,23 @@ void Metaspace::global_initialize() {
"archive file not closed or shared spaces not disabled.");
}
}
#endif // INCLUDE_CDS
#ifdef _LP64
// If UseCompressedClassPointers is set then allocate the metaspace area
// above the heap and above the CDS area (if it exists).
if (using_class_space()) {
if (UseSharedSpaces) {
#if INCLUDE_CDS
char* cds_end = (char*)(cds_address + cds_total);
cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment);
allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
#endif
} else {
char* base = (char*)align_ptr_up(Universe::heap()->reserved_region().end(), _reserve_alignment);
allocate_metaspace_compressed_klass_ptrs(base, 0);
}
}
#endif
#endif // _LP64
// Initialize these before initializing the VirtualSpaceList
_first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord;
......@@ -3366,6 +3378,10 @@ size_t Metaspace::capacity_bytes_slow(MetadataType mdtype) const {
void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
if (SafepointSynchronize::is_at_safepoint()) {
if (DumpSharedSpaces && PrintSharedSpaces) {
record_deallocation(ptr, vsm()->get_raw_word_size(word_size));
}
assert(Thread::current()->is_VM_thread(), "should be the VM thread");
// Don't take Heap_lock
MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
......@@ -3420,8 +3436,9 @@ MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
if (result == NULL) {
report_out_of_shared_space(read_only ? SharedReadOnly : SharedReadWrite);
}
space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size));
if (PrintSharedSpaces) {
space->record_allocation(result, type, space->vsm()->get_raw_word_size(word_size));
}
// Zero initialize.
Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
......@@ -3520,13 +3537,53 @@ const char* Metaspace::metadata_type_name(Metaspace::MetadataType mdtype) {
void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) {
assert(DumpSharedSpaces, "sanity");
AllocRecord *rec = new AllocRecord((address)ptr, type, (int)word_size * HeapWordSize);
int byte_size = (int)word_size * HeapWordSize;
AllocRecord *rec = new AllocRecord((address)ptr, type, byte_size);
if (_alloc_record_head == NULL) {
_alloc_record_head = _alloc_record_tail = rec;
} else {
} else if (_alloc_record_tail->_ptr + _alloc_record_tail->_byte_size == (address)ptr) {
_alloc_record_tail->_next = rec;
_alloc_record_tail = rec;
} else {
// slow linear search, but this doesn't happen that often, and only when dumping
for (AllocRecord *old = _alloc_record_head; old; old = old->_next) {
if (old->_ptr == ptr) {
assert(old->_type == MetaspaceObj::DeallocatedType, "sanity");
int remain_bytes = old->_byte_size - byte_size;
assert(remain_bytes >= 0, "sanity");
old->_type = type;
if (remain_bytes == 0) {
delete(rec);
} else {
address remain_ptr = address(ptr) + byte_size;
rec->_ptr = remain_ptr;
rec->_byte_size = remain_bytes;
rec->_type = MetaspaceObj::DeallocatedType;
rec->_next = old->_next;
old->_byte_size = byte_size;
old->_next = rec;
}
return;
}
}
assert(0, "reallocating a freed pointer that was not recorded");
}
}
void Metaspace::record_deallocation(void* ptr, size_t word_size) {
assert(DumpSharedSpaces, "sanity");
for (AllocRecord *rec = _alloc_record_head; rec; rec = rec->_next) {
if (rec->_ptr == ptr) {
assert(rec->_byte_size == (int)word_size * HeapWordSize, "sanity");
rec->_type = MetaspaceObj::DeallocatedType;
return;
}
}
assert(0, "deallocating a pointer that was not recorded");
}
void Metaspace::iterate(Metaspace::AllocRecordClosure *closure) {
......
......@@ -171,9 +171,10 @@ class Metaspace : public CHeapObj<mtClass> {
static const MetaspaceTracer* tracer() { return _tracer; }
private:
// This is used by DumpSharedSpaces only, where only _vsm is used. So we will
// These 2 methods are used by DumpSharedSpaces only, where only _vsm is used. So we will
// maintain a single list for now.
void record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size);
void record_deallocation(void* ptr, size_t word_size);
#ifdef _LP64
static void set_narrow_klass_base_and_shift(address metaspace_base, address cds_base);
......
......@@ -26,6 +26,7 @@
#include "classfile/dictionary.hpp"
#include "classfile/loaderConstraints.hpp"
#include "classfile/placeholders.hpp"
#include "classfile/sharedClassUtil.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
......@@ -46,6 +47,10 @@ int MetaspaceShared::_max_alignment = 0;
ReservedSpace* MetaspaceShared::_shared_rs = NULL;
bool MetaspaceShared::_link_classes_made_progress;
bool MetaspaceShared::_check_classes_made_progress;
bool MetaspaceShared::_has_error_classes;
bool MetaspaceShared::_archive_loading_failed = false;
// Read/write a data stream for restoring/preserving metadata pointers and
// miscellaneous data from/to the shared archive file.
......@@ -445,6 +450,23 @@ void VM_PopulateDumpSharedSpace::doit() {
SystemDictionary::classes_do(collect_classes);
tty->print_cr("Number of classes %d", _global_klass_objects->length());
{
int num_type_array = 0, num_obj_array = 0, num_inst = 0;
for (int i = 0; i < _global_klass_objects->length(); i++) {
Klass* k = _global_klass_objects->at(i);
if (k->oop_is_instance()) {
num_inst ++;
} else if (k->oop_is_objArray()) {
num_obj_array ++;
} else {
assert(k->oop_is_typeArray(), "sanity");
num_type_array ++;
}
}
tty->print_cr(" instance classes = %5d", num_inst);
tty->print_cr(" obj array classes = %5d", num_obj_array);
tty->print_cr(" type array classes = %5d", num_type_array);
}
// Update all the fingerprints in the shared methods.
tty->print("Calculating fingerprints ... ");
......@@ -610,38 +632,58 @@ void VM_PopulateDumpSharedSpace::doit() {
#undef fmt_space
}
static void link_shared_classes(Klass* obj, TRAPS) {
void MetaspaceShared::link_one_shared_class(Klass* obj, TRAPS) {
Klass* k = obj;
if (k->oop_is_instance()) {
InstanceKlass* ik = (InstanceKlass*) k;
// Link the class to cause the bytecodes to be rewritten and the
// cpcache to be created.
if (ik->init_state() < InstanceKlass::linked) {
ik->link_class(THREAD);
guarantee(!HAS_PENDING_EXCEPTION, "exception in class rewriting");
}
// cpcache to be created. Class verification is done according
// to -Xverify setting.
_link_classes_made_progress |= try_link_class(ik, THREAD);
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
}
}
void MetaspaceShared::check_one_shared_class(Klass* k) {
if (k->oop_is_instance() && InstanceKlass::cast(k)->check_sharing_error_state()) {
_check_classes_made_progress = true;
}
}
// Support for a simple checksum of the contents of the class list
// file to prevent trivial tampering. The algorithm matches that in
// the MakeClassList program used by the J2SE build process.
#define JSUM_SEED ((jlong)CONST64(0xcafebabebabecafe))
static jlong
jsum(jlong start, const char *buf, const int len)
{
jlong h = start;
char *p = (char *)buf, *e = p + len;
while (p < e) {
char c = *p++;
if (c <= ' ') {
/* Skip spaces and control characters */
continue;
}
h = 31 * h + c;
void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
// We need to iterate because verification may cause additional classes
// to be loaded.
do {
_link_classes_made_progress = false;
SystemDictionary::classes_do(link_one_shared_class, THREAD);
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
} while (_link_classes_made_progress);
if (_has_error_classes) {
// Mark all classes whose super class or interfaces failed verification.
do {
// Not completely sure if we need to do this iteratively. Anyway,
// we should come here only if there are unverifiable classes, which
// shouldn't happen in normal cases. So better safe than sorry.
_check_classes_made_progress = false;
SystemDictionary::classes_do(check_one_shared_class);
} while (_check_classes_made_progress);
if (IgnoreUnverifiableClassesDuringDump) {
// This is useful when running JCK or SQE tests. You should not
// enable this when running real apps.
SystemDictionary::remove_classes_in_error_state();
} else {
tty->print_cr("Please remove the unverifiable classes from your class list and try again");
exit(1);
}
return h;
}
}
void MetaspaceShared::prepare_for_dumping() {
ClassLoader::initialize_shared_path();
FileMapInfo::allocate_classpath_entry_table();
}
// Preload classes from a list, populate the shared spaces and dump to a
......@@ -650,72 +692,112 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
TraceTime timer("Dump Shared Spaces", TraceStartupTime);
ResourceMark rm;
tty->print_cr("Allocated shared space: %d bytes at " PTR_FORMAT,
MetaspaceShared::shared_rs()->size(),
MetaspaceShared::shared_rs()->base());
// Preload classes to be shared.
// Should use some os:: method rather than fopen() here. aB.
// Construct the path to the class list (in jre/lib)
// Walk up two directories from the location of the VM and
// optionally tack on "lib" (depending on platform)
char class_list_path[JVM_MAXPATHLEN];
os::jvm_path(class_list_path, sizeof(class_list_path));
for (int i = 0; i < 3; i++) {
char *end = strrchr(class_list_path, *os::file_separator());
if (end != NULL) *end = '\0';
}
int class_list_path_len = (int)strlen(class_list_path);
if (class_list_path_len >= 3) {
if (strcmp(class_list_path + class_list_path_len - 3, "lib") != 0) {
strcat(class_list_path, os::file_separator());
strcat(class_list_path, "lib");
const char* class_list_path;
if (SharedClassListFile == NULL) {
// Construct the path to the class list (in jre/lib)
// Walk up two directories from the location of the VM and
// optionally tack on "lib" (depending on platform)
char class_list_path_str[JVM_MAXPATHLEN];
os::jvm_path(class_list_path_str, sizeof(class_list_path_str));
for (int i = 0; i < 3; i++) {
char *end = strrchr(class_list_path_str, *os::file_separator());
if (end != NULL) *end = '\0';
}
int class_list_path_len = (int)strlen(class_list_path_str);
if (class_list_path_len >= 3) {
if (strcmp(class_list_path_str + class_list_path_len - 3, "lib") != 0) {
strcat(class_list_path_str, os::file_separator());
strcat(class_list_path_str, "lib");
}
}
strcat(class_list_path_str, os::file_separator());
strcat(class_list_path_str, "classlist");
class_list_path = class_list_path_str;
} else {
class_list_path = SharedClassListFile;
}
strcat(class_list_path, os::file_separator());
strcat(class_list_path, "classlist");
FILE* file = fopen(class_list_path, "r");
if (file != NULL) {
jlong computed_jsum = JSUM_SEED;
jlong file_jsum = 0;
int class_count = 0;
GrowableArray<Klass*>* class_promote_order = new GrowableArray<Klass*>();
char class_name[256];
int class_count = 0;
GrowableArray<Klass*>* class_promote_order = new GrowableArray<Klass*>();
// sun.io.Converters
static const char obj_array_sig[] = "[[Ljava/lang/Object;";
SymbolTable::new_permanent_symbol(obj_array_sig, THREAD);
// sun.io.Converters
static const char obj_array_sig[] = "[[Ljava/lang/Object;";
SymbolTable::new_permanent_symbol(obj_array_sig, THREAD);
// java.util.HashMap
static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;";
SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD);
// java.util.HashMap
static const char map_entry_array_sig[] = "[Ljava/util/Map$Entry;";
SymbolTable::new_permanent_symbol(map_entry_array_sig, THREAD);
tty->print_cr("Loading classes to share ...");
_has_error_classes = false;
class_count += preload_and_dump(class_list_path, class_promote_order,
THREAD);
if (ExtraSharedClassListFile) {
class_count += preload_and_dump(ExtraSharedClassListFile, class_promote_order,
THREAD);
}
tty->print_cr("Loading classes to share: done.");
tty->print("Loading classes to share ... ");
while ((fgets(class_name, sizeof class_name, file)) != NULL) {
if (*class_name == '#') {
jint fsh, fsl;
if (sscanf(class_name, "# %8x%8x\n", &fsh, &fsl) == 2) {
file_jsum = ((jlong)(fsh) << 32) | (fsl & 0xffffffff);
}
if (PrintSharedSpaces) {
tty->print_cr("Shared spaces: preloaded %d classes", class_count);
}
// Rewrite and link classes
tty->print_cr("Rewriting and linking classes ...");
// Link any classes which got missed. This would happen if we have loaded classes that
// were not explicitly specified in the classlist. E.g., if an interface implemented by class K
// fails verification, all other interfaces that were not specified in the classlist but
// are implemented by K are not verified.
link_and_cleanup_shared_classes(CATCH);
tty->print_cr("Rewriting and linking classes: done");
// Create and dump the shared spaces. Everything so far is loaded
// with the null class loader.
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
VM_PopulateDumpSharedSpace op(loader_data, class_promote_order);
VMThread::execute(&op);
// Since various initialization steps have been undone by this process,
// it is not reasonable to continue running a java process.
exit(0);
}
int MetaspaceShared::preload_and_dump(const char * class_list_path,
GrowableArray<Klass*>* class_promote_order,
TRAPS) {
FILE* file = fopen(class_list_path, "r");
char class_name[256];
int class_count = 0;
if (file != NULL) {
while ((fgets(class_name, sizeof class_name, file)) != NULL) {
if (*class_name == '#') { // comment
continue;
}
// Remove trailing newline
size_t name_len = strlen(class_name);
class_name[name_len-1] = '\0';
computed_jsum = jsum(computed_jsum, class_name, (const int)name_len - 1);
if (class_name[name_len-1] == '\n') {
class_name[name_len-1] = '\0';
}
// Got a class name - load it.
TempNewSymbol class_name_symbol = SymbolTable::new_permanent_symbol(class_name, THREAD);
guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol.");
Klass* klass = SystemDictionary::resolve_or_null(class_name_symbol,
THREAD);
guarantee(!HAS_PENDING_EXCEPTION, "Exception resolving a class.");
CLEAR_PENDING_EXCEPTION;
if (klass != NULL) {
if (PrintSharedSpaces && Verbose && WizardMode) {
tty->print_cr("Shared spaces preloaded: %s", class_name);
}
InstanceKlass* ik = InstanceKlass::cast(klass);
// Should be class load order as per -XX:+TraceClassLoadingPreorder
......@@ -725,52 +807,14 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
// cpcache to be created. The linking is done as soon as classes
// are loaded in order that the related data structures (klass and
// cpCache) are located together.
if (ik->init_state() < InstanceKlass::linked) {
ik->link_class(THREAD);
guarantee(!(HAS_PENDING_EXCEPTION), "exception in class rewriting");
}
// TODO: Resolve klasses in constant pool
ik->constants()->resolve_class_constants(THREAD);
try_link_class(ik, THREAD);
guarantee(!HAS_PENDING_EXCEPTION, "exception in link_class");
class_count++;
} else {
if (PrintSharedSpaces && Verbose && WizardMode) {
tty->cr();
tty->print_cr(" Preload failed: %s", class_name);
}
//tty->print_cr("Preload failed: %s", class_name);
}
file_jsum = 0; // Checksum must be on last line of file
}
if (computed_jsum != file_jsum) {
tty->cr();
tty->print_cr("Preload failed: checksum of class list was incorrect.");
exit(1);
}
tty->print_cr("done. ");
if (PrintSharedSpaces) {
tty->print_cr("Shared spaces: preloaded %d classes", class_count);
}
// Rewrite and unlink classes.
tty->print("Rewriting and linking classes ... ");
// Link any classes which got missed. (It's not quite clear why
// they got missed.) This iteration would be unsafe if we weren't
// single-threaded at this point; however we can't do it on the VM
// thread because it requires object allocation.
SystemDictionary::classes_do(link_shared_classes, CATCH);
tty->print_cr("done. ");
// Create and dump the shared spaces. Everything so far is loaded
// with the null class loader.
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
VM_PopulateDumpSharedSpace op(loader_data, class_promote_order);
VMThread::execute(&op);
} else {
char errmsg[JVM_MAXPATHLEN];
os::lasterror(errmsg, JVM_MAXPATHLEN);
......@@ -778,11 +822,39 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
exit(1);
}
// Since various initialization steps have been undone by this process,
// it is not reasonable to continue running a java process.
exit(0);
return class_count;
}
// Returns true if the class's status has changed
bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) {
assert(DumpSharedSpaces, "should only be called during dumping");
if (ik->init_state() < InstanceKlass::linked) {
bool saved = BytecodeVerificationLocal;
if (!SharedClassUtil::is_shared_boot_class(ik)) {
// The verification decision is based on BytecodeVerificationRemote
// for non-system classes. Since we are using the NULL classloader
// to load non-system classes during dumping, we need to temporarily
// change BytecodeVerificationLocal to be the same as
// BytecodeVerificationRemote. Note this can cause the parent system
// classes also being verified. The extra overhead is acceptable during
// dumping.
BytecodeVerificationLocal = BytecodeVerificationRemote;
}
ik->link_class(THREAD);
if (HAS_PENDING_EXCEPTION) {
ResourceMark rm;
tty->print_cr("Preload Error: Verification failed for %s",
ik->external_name());
CLEAR_PENDING_EXCEPTION;
ik->set_in_error_state();
_has_error_classes = true;
}
BytecodeVerificationLocal = saved;
return true;
} else {
return false;
}
}
// Closure for serializing initialization data in from a data area
// (ptr_array) read from the shared file.
......@@ -866,7 +938,8 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
(_rw_base = mapinfo->map_region(rw)) != NULL &&
(_md_base = mapinfo->map_region(md)) != NULL &&
(_mc_base = mapinfo->map_region(mc)) != NULL &&
(image_alignment == (size_t)max_alignment())) {
(image_alignment == (size_t)max_alignment()) &&
mapinfo->validate_classpath_entry_table()) {
// Success (no need to do anything)
return true;
} else {
......@@ -883,7 +956,7 @@ bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
// If -Xshare:on is specified, print out the error message and exit VM,
// otherwise, set UseSharedSpaces to false and continue.
if (RequireSharedSpaces) {
vm_exit_during_initialization("Unable to use shared archive.", NULL);
vm_exit_during_initialization("Unable to use shared archive.", "Failed map_region for using -Xshare:on.");
} else {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
}
......@@ -983,6 +1056,20 @@ void MetaspaceShared::initialize_shared_spaces() {
// Close the mapinfo file
mapinfo->close();
if (PrintSharedArchiveAndExit) {
if (PrintSharedDictionary) {
tty->print_cr("\nShared classes:\n");
SystemDictionary::print_shared(false);
}
if (_archive_loading_failed) {
tty->print_cr("archive is invalid");
vm_exit(1);
} else {
tty->print_cr("archive is valid");
vm_exit(0);
}
}
}
// JVM/TI RedefineClasses() support:
......
......@@ -38,7 +38,10 @@ class MetaspaceShared : AllStatic {
// CDS support
static ReservedSpace* _shared_rs;
static int _max_alignment;
static bool _link_classes_made_progress;
static bool _check_classes_made_progress;
static bool _has_error_classes;
static bool _archive_loading_failed;
public:
enum {
vtbl_list_size = 17, // number of entries in the shared space vtable list.
......@@ -67,7 +70,11 @@ class MetaspaceShared : AllStatic {
NOT_CDS(return 0);
}
static void prepare_for_dumping() NOT_CDS_RETURN;
static void preload_and_dump(TRAPS) NOT_CDS_RETURN;
static int preload_and_dump(const char * class_list_path,
GrowableArray<Klass*>* class_promote_order,
TRAPS) NOT_CDS_RETURN;
static ReservedSpace* shared_rs() {
CDS_ONLY(return _shared_rs);
......@@ -78,6 +85,9 @@ class MetaspaceShared : AllStatic {
CDS_ONLY(_shared_rs = rs;)
}
static void set_archive_loading_failed() {
_archive_loading_failed = true;
}
static bool map_shared_spaces(FileMapInfo* mapinfo) NOT_CDS_RETURN_(false);
static void initialize_shared_spaces() NOT_CDS_RETURN;
......@@ -97,5 +107,10 @@ class MetaspaceShared : AllStatic {
static bool remap_shared_readonly_as_readwrite() NOT_CDS_RETURN_(true);
static void print_shared_spaces();
static bool try_link_class(InstanceKlass* ik, TRAPS);
static void link_one_shared_class(Klass* obj, TRAPS);
static void check_one_shared_class(Klass* obj);
static void link_and_cleanup_shared_classes(TRAPS);
};
#endif // SHARE_VM_MEMORY_METASPACE_SHARED_HPP
......@@ -26,6 +26,9 @@
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.hpp"
#if INCLUDE_CDS
#include "classfile/sharedClassUtil.hpp"
#endif
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
......@@ -34,6 +37,7 @@
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/cardTableModRefBS.hpp"
#include "memory/filemap.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/genCollectedHeap.hpp"
#include "memory/genRemSet.hpp"
......@@ -238,8 +242,9 @@ void Universe::check_alignment(uintx size, uintx alignment, const char* name) {
void initialize_basic_type_klass(Klass* k, TRAPS) {
Klass* ok = SystemDictionary::Object_klass();
if (UseSharedSpaces) {
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
assert(k->super() == ok, "u3");
k->restore_unshareable_info(CHECK);
k->restore_unshareable_info(loader_data, Handle(), CHECK);
} else {
k->initialize_supers(ok, CHECK);
}
......@@ -665,6 +670,10 @@ jint universe_init() {
SymbolTable::create_table();
StringTable::create_table();
ClassLoader::create_package_info_table();
if (DumpSharedSpaces) {
MetaspaceShared::prepare_for_dumping();
}
}
return JNI_OK;
......@@ -1166,6 +1175,11 @@ bool universe_post_init() {
MemoryService::add_metaspace_memory_pools();
MemoryService::set_universe_heap(Universe::_collectedHeap);
#if INCLUDE_CDS
if (UseSharedSpaces) {
SharedClassUtil::initialize(CHECK_false);
}
#endif
return true;
}
......
......@@ -186,8 +186,9 @@ void ArrayKlass::remove_unshareable_info() {
set_component_mirror(NULL);
}
void ArrayKlass::restore_unshareable_info(TRAPS) {
Klass::restore_unshareable_info(CHECK);
void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
assert(loader_data == ClassLoaderData::the_null_class_loader_data(), "array classes belong to null loader");
Klass::restore_unshareable_info(loader_data, protection_domain, CHECK);
// Klass recreates the component mirror also
}
......
......@@ -137,7 +137,7 @@ class ArrayKlass: public Klass {
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
virtual void restore_unshareable_info(TRAPS);
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
// Printing
void print_on(outputStream* st) const;
......
......@@ -2321,12 +2321,14 @@ void InstanceKlass::remove_unshareable_info() {
array_klasses_do(remove_unshareable_in_class);
}
void restore_unshareable_in_class(Klass* k, TRAPS) {
k->restore_unshareable_info(CHECK);
static void restore_unshareable_in_class(Klass* k, TRAPS) {
// Array classes have null protection domain.
// --> see ArrayKlass::complete_create_array_klass()
k->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
}
void InstanceKlass::restore_unshareable_info(TRAPS) {
Klass::restore_unshareable_info(CHECK);
void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
Klass::restore_unshareable_info(loader_data, protection_domain, CHECK);
instanceKlassHandle ik(THREAD, this);
Array<Method*>* methods = ik->methods();
......@@ -2352,6 +2354,38 @@ void InstanceKlass::restore_unshareable_info(TRAPS) {
ik->array_klasses_do(restore_unshareable_in_class, CHECK);
}
// returns true IFF is_in_error_state() has been changed as a result of this call.
bool InstanceKlass::check_sharing_error_state() {
assert(DumpSharedSpaces, "should only be called during dumping");
bool old_state = is_in_error_state();
if (!is_in_error_state()) {
bool bad = false;
for (InstanceKlass* sup = java_super(); sup; sup = sup->java_super()) {
if (sup->is_in_error_state()) {
bad = true;
break;
}
}
if (!bad) {
Array<Klass*>* interfaces = transitive_interfaces();
for (int i = 0; i < interfaces->length(); i++) {
Klass* iface = interfaces->at(i);
if (InstanceKlass::cast(iface)->is_in_error_state()) {
bad = true;
break;
}
}
}
if (bad) {
set_in_error_state();
}
}
return (old_state != is_in_error_state());
}
static void clear_all_breakpoints(Method* m) {
m->clear_all_breakpoints();
}
......
......@@ -1004,6 +1004,13 @@ class InstanceKlass: public Klass {
u2 idnum_allocated_count() const { return _idnum_allocated_count; }
public:
void set_in_error_state() {
assert(DumpSharedSpaces, "only call this when dumping archive");
_init_state = initialization_error;
}
bool check_sharing_error_state();
private:
// initialization state
#ifdef ASSERT
......@@ -1062,7 +1069,7 @@ private:
public:
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
virtual void restore_unshareable_info(TRAPS);
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
// jvm support
jint compute_modifier_flags(TRAPS) const;
......
......@@ -184,6 +184,7 @@ Klass::Klass() {
// The klass doesn't have any references at this point.
clear_modified_oops();
clear_accumulated_modified_oops();
_shared_class_path_index = -1;
}
jint Klass::array_layout_helper(BasicType etype) {
......@@ -508,27 +509,25 @@ void Klass::remove_unshareable_info() {
set_class_loader_data(NULL);
}
void Klass::restore_unshareable_info(TRAPS) {
void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
TRACE_INIT_ID(this);
// If an exception happened during CDS restore, some of these fields may already be
// set. We leave the class on the CLD list, even if incomplete so that we don't
// modify the CLD list outside a safepoint.
if (class_loader_data() == NULL) {
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
// Restore class_loader_data to the null class loader data
// Restore class_loader_data
set_class_loader_data(loader_data);
// Add to null class loader list first before creating the mirror
// Add to class loader list first before creating the mirror
// (same order as class file parsing)
loader_data->add_class(this);
}
// Recreate the class mirror. The protection_domain is always null for
// boot loader, for now.
// Recreate the class mirror.
// Only recreate it if not present. A previous attempt to restore may have
// gotten an OOM later but keep the mirror if it was created.
if (java_mirror() == NULL) {
java_lang_Class::create_mirror(this, Handle(NULL), CHECK);
java_lang_Class::create_mirror(this, protection_domain, CHECK);
}
}
......
......@@ -175,6 +175,16 @@ class Klass : public Metadata {
jbyte _modified_oops; // Card Table Equivalent (YC/CMS support)
jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
private:
// This is an index into FileMapHeader::_classpath_entry_table[], to
// associate this class with the JAR file where it's loaded from during
// dump time. If a class is not loaded from the shared archive, this field is
// -1.
jshort _shared_class_path_index;
friend class SharedClassUtil;
protected:
// Constructor
Klass();
......@@ -281,6 +291,15 @@ class Klass : public Metadata {
void clear_accumulated_modified_oops() { _accumulated_modified_oops = 0; }
bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; }
int shared_classpath_index() const {
return _shared_class_path_index;
};
void set_shared_classpath_index(int index) {
_shared_class_path_index = index;
};
protected: // internal accessors
Klass* subklass_oop() const { return _subklass; }
Klass* next_sibling_oop() const { return _next_sibling; }
......@@ -452,7 +471,7 @@ class Klass : public Metadata {
public:
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
virtual void restore_unshareable_info(TRAPS);
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
protected:
// computes the subtype relationship
......
......@@ -28,6 +28,10 @@
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#if INCLUDE_CDS
#include "classfile/sharedClassUtil.hpp"
#include "classfile/systemDictionaryShared.hpp"
#endif
#include "classfile/vmSymbols.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecode.hpp"
......@@ -996,7 +1000,15 @@ JVM_ENTRY(jclass, JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name)
h_loader,
Handle(),
CHECK_NULL);
#if INCLUDE_CDS
if (k == NULL) {
// If the class is not already loaded, try to see if it's in the shared
// archive for the current classloader (h_loader).
instanceKlassHandle ik = SystemDictionaryShared::find_or_load_shared_class(
klass_name, h_loader, CHECK_NULL);
k = ik();
}
#endif
return (k == NULL) ? NULL :
(jclass) JNIHandles::make_local(env, k->java_mirror());
JVM_END
......
......@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaAssertions.hpp"
#include "classfile/symbolTable.hpp"
#include "compiler/compilerOracle.hpp"
......@@ -40,6 +41,7 @@
#include "services/memTracker.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/macros.hpp"
#include "utilities/stringUtils.hpp"
#include "utilities/taskqueue.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
......@@ -1109,11 +1111,11 @@ void Arguments::set_mode_flags(Mode mode) {
// Conflict: required to use shared spaces (-Xshare:on), but
// incompatible command line options were chosen.
static void no_shared_spaces() {
static void no_shared_spaces(const char* message) {
if (RequireSharedSpaces) {
jio_fprintf(defaultStream::error_stream(),
"Class data sharing is inconsistent with other specified options.\n");
vm_exit_during_initialization("Unable to use shared archive.", NULL);
vm_exit_during_initialization("Unable to use shared archive.", message);
} else {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
}
......@@ -1554,7 +1556,7 @@ void Arguments::set_ergonomics_flags() {
// at link time, or rewrite bytecodes in non-shared methods.
if (!DumpSharedSpaces && !RequireSharedSpaces &&
(FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) {
no_shared_spaces();
no_shared_spaces("COMPILER2 default: -Xshare:auto | off, have to manually setup to on.");
}
#endif
......@@ -3243,6 +3245,15 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
}
}
// PrintSharedArchiveAndExit will turn on
// -Xshare:on
// -XX:+TraceClassPaths
if (PrintSharedArchiveAndExit) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true);
FLAG_SET_CMDLINE(bool, TraceClassPaths, true);
}
// Change the default value for flags which have different default values
// when working with older JDKs.
#ifdef LINUX
......@@ -3251,9 +3262,55 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
FLAG_SET_DEFAULT(UseLinuxPosixThreadCPUClocks, false);
}
#endif // LINUX
fix_appclasspath();
return JNI_OK;
}
// Remove all empty paths from the app classpath (if IgnoreEmptyClassPaths is enabled)
//
// This is necessary because some apps like to specify classpath like -cp foo.jar:${XYZ}:bar.jar
// in their start-up scripts. If XYZ is empty, the classpath will look like "-cp foo.jar::bar.jar".
// Java treats such empty paths as if the user specified "-cp foo.jar:.:bar.jar". I.e., an empty
// path is treated as the current directory.
//
// This causes problems with CDS, which requires that all directories specified in the classpath
// must be empty. In most cases, applications do NOT want to load classes from the current
// directory anyway. Adding -XX:+IgnoreEmptyClassPaths will make these applications' start-up
// scripts compatible with CDS.
void Arguments::fix_appclasspath() {
if (IgnoreEmptyClassPaths) {
const char separator = *os::path_separator();
const char* src = _java_class_path->value();
// skip over all the leading empty paths
while (*src == separator) {
src ++;
}
char* copy = AllocateHeap(strlen(src) + 1, mtInternal);
strncpy(copy, src, strlen(src) + 1);
// trim all trailing empty paths
for (char* tail = copy + strlen(copy) - 1; tail >= copy && *tail == separator; tail--) {
*tail = '\0';
}
char from[3] = {separator, separator, '\0'};
char to [2] = {separator, '\0'};
while (StringUtils::replace_no_expand(copy, from, to) > 0) {
// Keep replacing "::" -> ":" until we have no more "::" (non-windows)
// Keep replacing ";;" -> ";" until we have no more ";;" (windows)
}
_java_class_path->set_value(copy);
FreeHeap(copy); // a copy was made by set_value, so don't need this anymore
}
if (!PrintSharedArchiveAndExit) {
ClassLoader::trace_class_path("[classpath: ", _java_class_path->value());
}
}
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();
......@@ -3424,9 +3481,8 @@ void Arguments::set_shared_spaces_flags() {
"Cannot dump shared archive when UseCompressedOops or UseCompressedClassPointers is off.", NULL);
}
} else {
// UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces.
if (!UseCompressedOops || !UseCompressedClassPointers) {
no_shared_spaces();
no_shared_spaces("UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces.");
}
#endif
}
......@@ -3684,7 +3740,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
FLAG_SET_DEFAULT(PrintSharedSpaces, false);
}
no_shared_spaces();
no_shared_spaces("CDS Disabled");
#endif // INCLUDE_CDS
return JNI_OK;
......
......@@ -577,12 +577,15 @@ class Arguments : AllStatic {
_meta_index_dir = meta_index_dir;
}
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_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_appclasspath() { return _java_class_path->value(); }
static void fix_appclasspath();
// Operation modi
static Mode mode() { return _mode; }
......
......@@ -2334,6 +2334,12 @@ class CommandLineFlags {
notproduct(bool, TraceScavenge, false, \
"Trace scavenge") \
\
product(bool, IgnoreEmptyClassPaths, false, \
"Ignore empty path elements in -classpath") \
\
product(bool, TraceClassPaths, false, \
"Trace processing of class paths") \
\
product_rw(bool, TraceClassLoading, false, \
"Trace all classes loaded") \
\
......@@ -3780,6 +3786,13 @@ class CommandLineFlags {
product(bool, PrintSharedSpaces, false, \
"Print usage of shared spaces") \
\
product(bool, PrintSharedArchiveAndExit, false, \
"Print shared archive file contents") \
\
product(bool, PrintSharedDictionary, false, \
"If PrintSharedArchiveAndExit is true, also print the shared " \
"dictionary") \
\
product(uintx, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M), \
"Size of read-write space for metadata (in bytes)") \
\
......@@ -3800,6 +3813,10 @@ class CommandLineFlags {
"support JSR 292 (method handles, invokedynamic, " \
"anonymous classes") \
\
diagnostic(bool, IgnoreUnverifiableClassesDuringDump, false, \
"Do not quit -Xshare:dump even if we encounter unverifiable " \
"classes. Just exclude them from the shared dictionary.") \
\
diagnostic(bool, PrintMethodHandleStubs, false, \
"Print generated stub code for method handles") \
\
......@@ -3895,9 +3912,19 @@ class CommandLineFlags {
product(bool , AllowNonVirtualCalls, false, \
"Obey the ACC_SUPER flag and allow invokenonvirtual calls") \
\
product(ccstr, DumpLoadedClassList, NULL, \
"Dump the names all loaded classes, that could be stored into " \
"the CDS archive, in the specified file") \
\
product(ccstr, SharedClassListFile, NULL, \
"Override the default CDS class list") \
\
diagnostic(ccstr, SharedArchiveFile, NULL, \
"Override the default location of the CDS archive file") \
\
product(ccstr, ExtraSharedClassListFile, NULL, \
"Extra classlist for building the CDS archive file") \
\
experimental(uintx, ArrayAllocatorMallocLimit, \
SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \
"Allocation less than this value will be allocated " \
......
......@@ -308,6 +308,10 @@ void JavaCalls::call(JavaValue* result, methodHandle method, JavaCallArguments*
}
void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArguments* args, TRAPS) {
// During dumping, Java execution environment is not fully initialized. Also, Java execution
// may cause undesirable side-effects in the class metadata.
assert(!DumpSharedSpaces, "must not execute Java bytecodes when dumping");
methodHandle method = *m;
JavaThread* thread = (JavaThread*)THREAD;
assert(thread->is_Java_thread(), "must be called by a java thread");
......
......@@ -320,7 +320,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList<Metablock> > MetablockTreeDicti
nonstatic_field(InstanceKlass, _jni_ids, JNIid*) \
nonstatic_field(InstanceKlass, _osr_nmethods_head, nmethod*) \
nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*) \
nonstatic_field(InstanceKlass, _generic_signature_index, u2) \
nonstatic_field(InstanceKlass, _generic_signature_index, u2) \
nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \
volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \
nonstatic_field(InstanceKlass, _annotations, Annotations*) \
......@@ -665,6 +665,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList<Metablock> > MetablockTreeDicti
static_field(SystemDictionary, WK_KLASS(StackOverflowError_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(ProtectionDomain_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(AccessControlContext_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(SecureClassLoader_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(Reference_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(SoftReference_klass), Klass*) \
static_field(SystemDictionary, WK_KLASS(WeakReference_klass), Klass*) \
......
......@@ -85,9 +85,13 @@ bool Exceptions::special_exception(Thread* thread, const char* file, int line, H
#endif // ASSERT
if (thread->is_VM_thread()
|| thread->is_Compiler_thread() ) {
|| thread->is_Compiler_thread()
|| DumpSharedSpaces ) {
// We do not care what kind of exception we get for the vm-thread or a thread which
// is compiling. We just install a dummy exception object
//
// We also cannot throw a proper exception when dumping, because we cannot run
// Java bytecodes now. A dummy exception will suffice.
thread->set_pending_exception(Universe::vm_exception(), file, line);
return true;
}
......@@ -108,9 +112,13 @@ bool Exceptions::special_exception(Thread* thread, const char* file, int line, S
}
if (thread->is_VM_thread()
|| thread->is_Compiler_thread() ) {
|| thread->is_Compiler_thread()
|| DumpSharedSpaces ) {
// We do not care what kind of exception we get for the vm-thread or a thread which
// is compiling. We just install a dummy exception object
//
// We also cannot throw a proper exception when dumping, because we cannot run
// Java bytecodes now. A dummy exception will suffice.
thread->set_pending_exception(Universe::vm_exception(), file, line);
return true;
}
......
......@@ -365,6 +365,7 @@ stringStream::~stringStream() {}
xmlStream* xtty;
outputStream* tty;
outputStream* gclog_or_tty;
CDS_ONLY(fileStream* classlist_file;) // Only dump the classes that can be stored into the CDS archive
extern Mutex* tty_lock;
#define EXTRACHARLEN 32
......@@ -476,7 +477,8 @@ static const char* make_log_name_internal(const char* log_name, const char* forc
return buf;
}
// log_name comes from -XX:LogFile=log_name or -Xloggc:log_name
// log_name comes from -XX:LogFile=log_name, -Xloggc:log_name or
// -XX:DumpLoadedClassList=<file_name>
// in log_name, %p => pid1234 and
// %t => YYYY-MM-DD_HH-MM-SS
static const char* make_log_name(const char* log_name, const char* force_directory) {
......@@ -1116,6 +1118,16 @@ void ostream_init_log() {
gclog_or_tty = gclog;
}
#if INCLUDE_CDS
// For -XX:DumpLoadedClassList=<file> option
if (DumpLoadedClassList != NULL) {
const char* list_name = make_log_name(DumpLoadedClassList, NULL);
classlist_file = new(ResourceObj::C_HEAP, mtInternal)
fileStream(list_name);
FREE_C_HEAP_ARRAY(char, list_name, mtInternal);
}
#endif
// If we haven't lazily initialized the logfile yet, do it now,
// to avoid the possibility of lazy initialization during a VM
// crash, which can affect the stability of the fatal error handler.
......@@ -1128,6 +1140,11 @@ void ostream_exit() {
static bool ostream_exit_called = false;
if (ostream_exit_called) return;
ostream_exit_called = true;
#if INCLUDE_CDS
if (classlist_file != NULL) {
delete classlist_file;
}
#endif
if (gclog_or_tty != tty) {
delete gclog_or_tty;
}
......
......@@ -214,6 +214,8 @@ class fileStream : public outputStream {
void flush();
};
CDS_ONLY(extern fileStream* classlist_file;)
// unlike fileStream, fdStream does unbuffered I/O by calling
// open() and write() directly. It is async-safe, but output
// from multiple thread may be mixed together. Used by fatal
......
/*
* 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 "utilities/stringUtils.hpp"
int StringUtils::replace_no_expand(char* string, const char* from, const char* to) {
int replace_count = 0;
size_t from_len = strlen(from);
size_t to_len = strlen(to);
assert(from_len >= to_len, "must not expand input");
for (char* dst = string; *dst && (dst = strstr(dst, from)) != NULL;) {
char* left_over = dst + from_len;
memmove(dst, to, to_len); // does not copy trailing 0 of <to>
dst += to_len; // skip over the replacement.
memmove(dst, left_over, strlen(left_over) + 1); // copies the trailing 0 of <left_over>
++ replace_count;
}
return replace_count;
}
/*
* 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_UTILITIES_STRINGUTILS_HPP
#define SHARE_VM_UTILITIES_STRINGUTILS_HPP
#include "memory/allocation.hpp"
class StringUtils : AllStatic {
public:
// Replace the substring <from> with another string <to>. <to> must be
// no longer than <from>. The input string is modified in-place.
//
// Replacement is done in a single pass left-to-right. So replace_no_expand("aaa", "aa", "a")
// will result in "aa", not "a".
//
// Returns the count of substrings that have been replaced.
static int replace_no_expand(char* string, const char* from, const char* to);
};
#endif // SHARE_VM_UTILITIES_STRINGUTILS_HPP
/*
* 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.
*/
package com.oracle.java.testlibrary;
import java.io.File;
import java.io.FileReader;
import java.util.Properties;
public class BuildHelper {
/**
* Commercial builds should have the BUILD_TYPE set to commercial
* within the release file, found at the root of the JDK.
*/
public static boolean isCommercialBuild() throws Exception {
String buildType = getReleaseProperty("BUILD_TYPE","notFound");
return buildType.equals("commercial");
}
/**
* Return the value for property key, or defaultValue if no property not found.
* If present, double quotes are trimmed.
*/
public static String getReleaseProperty(String key, String defaultValue) throws Exception {
Properties properties = getReleaseProperties();
String value = properties.getProperty(key, defaultValue);
return trimDoubleQuotes(value);
}
/**
* Return the value for property key, or null if no property not found.
* If present, double quotes are trimmed.
*/
public static String getReleaseProperty(String key) throws Exception {
return getReleaseProperty(key, null);
}
/**
* Get properties from the release file
*/
public static Properties getReleaseProperties() throws Exception {
Properties properties = new Properties();
properties.load(new FileReader(getReleaseFile()));
return properties;
}
/**
* Every JDK has a release file in its root.
* @return A handler to the release file.
*/
public static File getReleaseFile() throws Exception {
String jdkPath = getJDKRoot();
File releaseFile = new File(jdkPath,"release");
if ( ! releaseFile.canRead() ) {
throw new Exception("Release file is not readable, or it is absent: " +
releaseFile.getCanonicalPath());
}
return releaseFile;
}
/**
* Returns path to the JDK under test.
* This path is obtained through the test.jdk property, usually set by JTREG.
*/
public static String getJDKRoot() {
String jdkPath = System.getProperty("test.jdk");
if (jdkPath == null) {
throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. "
+ "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'.");
}
return jdkPath;
}
/**
* Trim double quotes from the beginning and the end of the given string.
* @param original string to trim.
* @return a new trimmed string.
*/
public static String trimDoubleQuotes(String original) {
if (original == null) { return null; }
String trimmed = original.replaceAll("^\"+|\"+$", "");
return trimmed;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册