8244778: Archive full module graph in CDS

Reviewed-by: erikj, coleenp, lfoltan, redestad, alanb, mchung
This commit is contained in:
Ioi Lam 2020-09-13 14:45:12 +00:00
parent 998ce78e53
commit 03a4df0acd
59 changed files with 2052 additions and 164 deletions

View File

@ -119,6 +119,7 @@ ifneq ($(call check-jvm-feature, cds), true)
archiveBuilder.cpp \
archiveUtils.cpp \
classListParser.cpp \
classLoaderDataShared.cpp \
classLoaderExt.cpp \
dumpAllocStats.cpp \
dynamicArchive.cpp \

View File

@ -198,5 +198,6 @@ JVM_AddModuleExports
JVM_AddModuleExportsToAll
JVM_AddModuleExportsToAllUnnamed
JVM_AddReadsModule
JVM_DefineArchivedModules
JVM_DefineModule
JVM_SetBootLoaderUnnamedModule

View File

@ -1644,12 +1644,14 @@ void ClassLoader::create_javabase() {
{
MutexLocker ml(THREAD, Module_lock);
ModuleEntry* jb_module = null_cld_modules->locked_create_entry(Handle(),
if (ModuleEntryTable::javabase_moduleEntry() == NULL) { // may have been inited by CDS.
ModuleEntry* jb_module = null_cld_modules->locked_create_entry(Handle(),
false, vmSymbols::java_base(), NULL, NULL, null_cld);
if (jb_module == NULL) {
vm_exit_during_initialization("Unable to create ModuleEntry for " JAVA_BASE_NAME);
if (jb_module == NULL) {
vm_exit_during_initialization("Unable to create ModuleEntry for " JAVA_BASE_NAME);
}
ModuleEntryTable::set_javabase_moduleEntry(jb_module);
}
ModuleEntryTable::set_javabase_moduleEntry(jb_module);
}
}

View File

@ -0,0 +1,202 @@
/*
* Copyright (c) 2020, 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/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
#include "logging/log.hpp"
#include "memory/metaspaceShared.hpp"
#include "runtime/handles.inline.hpp"
#if INCLUDE_CDS_JAVA_HEAP
class ArchivedClassLoaderData {
Array<PackageEntry*>* _packages;
Array<ModuleEntry*>* _modules;
void assert_valid(ClassLoaderData* loader_data) {
// loader_data may be NULL if the boot layer has loaded no modules for the platform or
// system loaders (e.g., if you create a custom JDK image with only java.base).
if (loader_data != NULL) {
assert(!loader_data->has_class_mirror_holder(),
"loaders for non-strong hidden classes or unsafe anonymous classes not supported");
}
}
public:
ArchivedClassLoaderData() : _packages(NULL), _modules(NULL) {}
void iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure);
void allocate(ClassLoaderData* loader_data);
void init_archived_entries(ClassLoaderData* loader_data);
void init_archived_oops(ClassLoaderData* loader_data);
void serialize(SerializeClosure* f) {
f->do_ptr((void**)&_packages);
f->do_ptr((void**)&_modules);
}
void restore(ClassLoaderData* loader_data, bool do_entries, bool do_oops);
};
static ArchivedClassLoaderData _archived_boot_loader_data;
static ArchivedClassLoaderData _archived_platform_loader_data;
static ArchivedClassLoaderData _archived_system_loader_data;
static ModuleEntry* _archived_javabase_moduleEntry = NULL;
void ArchivedClassLoaderData::iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure) {
assert(DumpSharedSpaces, "must be");
assert_valid(loader_data);
if (loader_data != NULL) {
loader_data->packages()->iterate_symbols(closure);
loader_data->modules() ->iterate_symbols(closure);
}
}
void ArchivedClassLoaderData::allocate(ClassLoaderData* loader_data) {
assert(DumpSharedSpaces, "must be");
assert_valid(loader_data);
if (loader_data != NULL) {
// We can't create hashtables at dump time because the hashcode depends on the
// address of the Symbols, which may be relocated at runtime due to ASLR.
// So we store the packages/modules in Arrays. At runtime, we create
// the hashtables using these arrays.
_packages = loader_data->packages()->allocate_archived_entries();
_modules = loader_data->modules() ->allocate_archived_entries();
}
}
void ArchivedClassLoaderData::init_archived_entries(ClassLoaderData* loader_data) {
assert(DumpSharedSpaces, "must be");
assert_valid(loader_data);
if (loader_data != NULL) {
loader_data->packages()->init_archived_entries(_packages);
loader_data->modules() ->init_archived_entries(_modules);
}
}
void ArchivedClassLoaderData::init_archived_oops(ClassLoaderData* loader_data) {
assert(DumpSharedSpaces, "must be");
assert_valid(loader_data);
if (loader_data != NULL) {
loader_data->modules()->init_archived_oops(_modules);
}
}
void ArchivedClassLoaderData::restore(ClassLoaderData* loader_data, bool do_entries, bool do_oops) {
assert(UseSharedSpaces, "must be");
assert_valid(loader_data);
if (_modules != NULL) { // Could be NULL if we have archived no modules for platform/system loaders
ModuleEntryTable* modules = loader_data->modules();
PackageEntryTable* packages = loader_data->packages();
MutexLocker m1(Module_lock);
if (do_entries) {
modules->load_archived_entries(loader_data, _modules);
packages->load_archived_entries(_packages);
}
if (do_oops) {
modules->restore_archived_oops(loader_data, _modules);
}
}
}
// ------------------------------
static ClassLoaderData* null_class_loader_data() {
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
assert(loader_data != NULL, "must be");
return loader_data;
}
static ClassLoaderData* java_platform_loader_data_or_null() {
return ClassLoaderData::class_loader_data_or_null(SystemDictionary::java_platform_loader());
}
static ClassLoaderData* java_system_loader_data_or_null() {
return ClassLoaderData::class_loader_data_or_null(SystemDictionary::java_system_loader());
}
void ClassLoaderDataShared::iterate_symbols(MetaspaceClosure* closure) {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_boot_loader_data.iterate_symbols (null_class_loader_data(), closure);
_archived_platform_loader_data.iterate_symbols(java_platform_loader_data_or_null(), closure);
_archived_system_loader_data.iterate_symbols (java_system_loader_data_or_null(), closure);
}
void ClassLoaderDataShared::allocate_archived_tables() {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_boot_loader_data.allocate (null_class_loader_data());
_archived_platform_loader_data.allocate(java_platform_loader_data_or_null());
_archived_system_loader_data.allocate (java_system_loader_data_or_null());
}
void ClassLoaderDataShared::init_archived_tables() {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_boot_loader_data.init_archived_entries (null_class_loader_data());
_archived_platform_loader_data.init_archived_entries(java_platform_loader_data_or_null());
_archived_system_loader_data.init_archived_entries (java_system_loader_data_or_null());
_archived_javabase_moduleEntry = ModuleEntry::get_archived_entry(ModuleEntryTable::javabase_moduleEntry());
}
void ClassLoaderDataShared::init_archived_oops() {
assert(DumpSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_boot_loader_data.init_archived_oops (null_class_loader_data());
_archived_platform_loader_data.init_archived_oops(java_platform_loader_data_or_null());
_archived_system_loader_data.init_archived_oops (java_system_loader_data_or_null());
}
void ClassLoaderDataShared::serialize(SerializeClosure* f) {
_archived_boot_loader_data.serialize(f);
_archived_platform_loader_data.serialize(f);
_archived_system_loader_data.serialize(f);
f->do_ptr((void**)&_archived_javabase_moduleEntry);
if (f->reading() && MetaspaceShared::use_full_module_graph()) {
// Must be done before ClassLoader::create_javabase()
_archived_boot_loader_data.restore(null_class_loader_data(), true, false);
ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry);
log_info(cds)("use_full_module_graph = true; java.base = " INTPTR_FORMAT,
p2i(_archived_javabase_moduleEntry));
}
}
oop ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data() {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_boot_loader_data.restore(null_class_loader_data(), false, true);
return _archived_javabase_moduleEntry->module();
}
void ClassLoaderDataShared::restore_java_platform_loader_from_archive(ClassLoaderData* loader_data) {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_platform_loader_data.restore(loader_data, true, true);
}
void ClassLoaderDataShared::restore_java_system_loader_from_archive(ClassLoaderData* loader_data) {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
_archived_system_loader_data.restore(loader_data, true, true);
}
#endif // INCLUDE_CDS_JAVA_HEAP

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2020, 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_CLASSFILE_CLASSLOADERDATASHARED_HPP
#define SHARE_CLASSFILE_CLASSLOADERDATASHARED_HPP
#include "memory/allStatic.hpp"
#include "oops/oopsHierarchy.hpp"
class ClassLoaderData;
class MetaspaceClosure;
class SerializeClosure;
class ClassLoaderDataShared : AllStatic {
public:
static void allocate_archived_tables();
static void iterate_symbols(MetaspaceClosure* closure);
static void init_archived_tables();
static void init_archived_oops();
static void serialize(SerializeClosure* f);
static oop restore_archived_oops_for_null_class_loader_data();
static void restore_java_platform_loader_from_archive(ClassLoaderData* loader_data);
static void restore_java_system_loader_from_archive(ClassLoaderData* loader_data);
};
#endif // SHARE_CLASSFILE_CLASSLOADERDATASHARED_HPP

View File

@ -3392,12 +3392,17 @@ void java_lang_Module::set_name(oop module, oop value) {
module->obj_field_put(_name_offset, value);
}
ModuleEntry* java_lang_Module::module_entry(oop module) {
ModuleEntry* java_lang_Module::module_entry_raw(oop module) {
assert(_module_entry_offset != 0, "Uninitialized module_entry_offset");
assert(module != NULL, "module can't be null");
assert(oopDesc::is_oop(module), "module must be oop");
ModuleEntry* module_entry = (ModuleEntry*)module->address_field(_module_entry_offset);
return module_entry;
}
ModuleEntry* java_lang_Module::module_entry(oop module) {
ModuleEntry* module_entry = module_entry_raw(module);
if (module_entry == NULL) {
// If the inject field containing the ModuleEntry* is null then return the
// class loader's unnamed module.
@ -4821,9 +4826,8 @@ bool JavaClasses::is_supported_for_archiving(oop obj) {
Klass* klass = obj->klass();
if (klass == SystemDictionary::ClassLoader_klass() || // ClassLoader::loader_data is malloc'ed.
klass == SystemDictionary::Module_klass() || // Module::module_entry is malloc'ed
// The next 3 classes are used to implement java.lang.invoke, and are not used directly in
// regular Java code. The implementation of java.lang.invoke uses generated anonymoys classes
// regular Java code. The implementation of java.lang.invoke uses generated anonymous classes
// (e.g., as referenced by ResolvedMethodName::vmholder) that are not yet supported by CDS.
// So for now we cannot not support these classes for archiving.
//

View File

@ -797,6 +797,7 @@ class java_lang_Module {
static void set_name(oop module, oop value);
static ModuleEntry* module_entry(oop module);
static ModuleEntry* module_entry_raw(oop module);
static void set_module_entry(oop module, ModuleEntry* module_entry);
friend class JavaClasses;

View File

@ -29,7 +29,11 @@
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "logging/log.hpp"
#include "memory/archiveBuilder.hpp"
#include "memory/archiveUtils.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/oopHandle.inline.hpp"
@ -40,6 +44,8 @@
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/ostream.hpp"
#include "utilities/quickSort.hpp"
#include "utilities/resourceHash.hpp"
ModuleEntry* ModuleEntryTable::_javabase_module = NULL;
@ -108,15 +114,15 @@ void ModuleEntry::set_version(Symbol* version) {
// Returns the shared ProtectionDomain
oop ModuleEntry::shared_protection_domain() {
return _pd.resolve();
return _shared_pd.resolve();
}
// Set the shared ProtectionDomain atomically
void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data,
Handle pd_h) {
// Create a handle for the shared ProtectionDomain and save it atomically.
// init_handle_locked checks if someone beats us setting the _pd cache.
loader_data->init_handle_locked(_pd, pd_h);
// init_handle_locked checks if someone beats us setting the _shared_pd cache.
loader_data->init_handle_locked(_shared_pd, pd_h);
}
// Returns true if this module can read module m
@ -362,6 +368,203 @@ ModuleEntryTable::~ModuleEntryTable() {
assert(new_entry_free_list() == NULL, "entry present on ModuleEntryTable's free list");
}
#if INCLUDE_CDS_JAVA_HEAP
typedef ResourceHashtable<
const ModuleEntry*,
ModuleEntry*,
primitive_hash<const ModuleEntry*>,
primitive_equals<const ModuleEntry*>,
557, // prime number
ResourceObj::C_HEAP> ArchivedModuleEntries;
static ArchivedModuleEntries* _archive_modules_entries = NULL;
ModuleEntry* ModuleEntry::allocate_archived_entry() const {
assert(is_named(), "unnamed packages/modules are not archived");
ModuleEntry* archived_entry = (ModuleEntry*)MetaspaceShared::read_write_space_alloc(sizeof(ModuleEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry));
if (_archive_modules_entries == NULL) {
_archive_modules_entries = new (ResourceObj::C_HEAP, mtClass)ArchivedModuleEntries();
}
assert(_archive_modules_entries->get(this) == NULL, "Each ModuleEntry must not be shared across ModuleEntryTables");
_archive_modules_entries->put(this, archived_entry);
return archived_entry;
}
ModuleEntry* ModuleEntry::get_archived_entry(ModuleEntry* orig_entry) {
ModuleEntry** ptr = _archive_modules_entries->get(orig_entry);
assert(ptr != NULL && *ptr != NULL, "must have been allocated");
return *ptr;
}
// This function is used to archive ModuleEntry::_reads and PackageEntry::_qualified_exports.
// GrowableArray cannot be directly archived, as it needs to be expandable at runtime.
// Write it out as an Array, and convert it back to GrowableArray at runtime.
Array<ModuleEntry*>* ModuleEntry::write_growable_array(GrowableArray<ModuleEntry*>* array) {
Array<ModuleEntry*>* archived_array = NULL;
int length = (array == NULL) ? 0 : array->length();
if (length > 0) {
archived_array = MetaspaceShared::new_ro_array<ModuleEntry*>(length);
for (int i = 0; i < length; i++) {
ModuleEntry* archived_entry = get_archived_entry(array->at(i));
archived_array->at_put(i, archived_entry);
ArchivePtrMarker::mark_pointer((address*)archived_array->adr_at(i));
}
}
return archived_array;
}
GrowableArray<ModuleEntry*>* ModuleEntry::restore_growable_array(Array<ModuleEntry*>* archived_array) {
GrowableArray<ModuleEntry*>* array = NULL;
int length = (archived_array == NULL) ? 0 : archived_array->length();
if (length > 0) {
array = new (ResourceObj::C_HEAP, mtModule)GrowableArray<ModuleEntry*>(length, mtModule);
for (int i = 0; i < length; i++) {
ModuleEntry* archived_entry = archived_array->at(i);
array->append(archived_entry);
}
}
return array;
}
void ModuleEntry::iterate_symbols(MetaspaceClosure* closure) {
closure->push(literal_addr()); // name
closure->push(&_version);
closure->push(&_location);
}
void ModuleEntry::init_as_archived_entry() {
Array<ModuleEntry*>* archived_reads = write_growable_array(_reads);
set_next(NULL);
set_hash(0x0); // re-init at runtime
_loader_data = NULL; // re-init at runtime
_shared_path_index = FileMapInfo::get_module_shared_path_index(_location);
if (literal() != NULL) {
set_literal(ArchiveBuilder::get_relocated_symbol(literal()));
ArchivePtrMarker::mark_pointer((address*)literal_addr());
}
_reads = (GrowableArray<ModuleEntry*>*)archived_reads;
if (_version != NULL) {
_version = ArchiveBuilder::get_relocated_symbol(_version);
}
if (_location != NULL) {
_location = ArchiveBuilder::get_relocated_symbol(_location);
}
ArchivePtrMarker::mark_pointer((address*)&_reads);
ArchivePtrMarker::mark_pointer((address*)&_version);
ArchivePtrMarker::mark_pointer((address*)&_location);
}
void ModuleEntry::init_archived_oops() {
assert(DumpSharedSpaces, "static dump only");
oop module_obj = module();
if (module_obj != NULL) {
oop m = HeapShared::find_archived_heap_object(module_obj);
assert(m != NULL, "sanity");
_archived_module_narrow_oop = CompressedOops::encode(m);
}
assert(shared_protection_domain() == NULL, "never set during -Xshare:dump");
// Clear handles and restore at run time. Handles cannot be archived.
OopHandle null_handle;
_module = null_handle;
}
void ModuleEntry::load_from_archive(ClassLoaderData* loader_data) {
set_loader_data(loader_data);
_reads = restore_growable_array((Array<ModuleEntry*>*)_reads);
JFR_ONLY(INIT_ID(this);)
}
void ModuleEntry::restore_archive_oops(ClassLoaderData* loader_data) {
Handle module_handle(Thread::current(), HeapShared::materialize_archived_object(_archived_module_narrow_oop));
assert(module_handle.not_null(), "huh");
set_module(loader_data->add_handle(module_handle));
// This was cleared to zero during dump time -- we didn't save the value
// because it may be affected by archive relocation.
java_lang_Module::set_module_entry(module_handle(), this);
if (loader_data->class_loader() != NULL) {
java_lang_Module::set_loader(module_handle(), loader_data->class_loader());
}
}
static int compare_module_by_name(ModuleEntry* a, ModuleEntry* b) {
assert(a == b || a->name() != b->name(), "no duplicated names");
return a->name()->fast_compare(b->name());
}
void ModuleEntryTable::iterate_symbols(MetaspaceClosure* closure) {
for (int i = 0; i < table_size(); ++i) {
for (ModuleEntry* m = bucket(i); m != NULL; m = m->next()) {
m->iterate_symbols(closure);
}
}
}
Array<ModuleEntry*>* ModuleEntryTable::allocate_archived_entries() {
Array<ModuleEntry*>* archived_modules = MetaspaceShared::new_rw_array<ModuleEntry*>(number_of_entries());
int n = 0;
for (int i = 0; i < table_size(); ++i) {
for (ModuleEntry* m = bucket(i); m != NULL; m = m->next()) {
archived_modules->at_put(n++, m);
}
}
if (n > 1) {
// Always allocate in the same order to produce deterministic archive.
QuickSort::sort(archived_modules->data(), n, (_sort_Fn)compare_module_by_name, true);
}
for (int i = 0; i < n; i++) {
archived_modules->at_put(i, archived_modules->at(i)->allocate_archived_entry());
ArchivePtrMarker::mark_pointer((address*)archived_modules->adr_at(i));
}
return archived_modules;
}
void ModuleEntryTable::init_archived_entries(Array<ModuleEntry*>* archived_modules) {
assert(DumpSharedSpaces, "dump time only");
for (int i = 0; i < archived_modules->length(); i++) {
ModuleEntry* archived_entry = archived_modules->at(i);
archived_entry->init_as_archived_entry();
}
}
void ModuleEntryTable::init_archived_oops(Array<ModuleEntry*>* archived_modules) {
assert(DumpSharedSpaces, "dump time only");
for (int i = 0; i < archived_modules->length(); i++) {
ModuleEntry* archived_entry = archived_modules->at(i);
archived_entry->init_archived_oops();
}
}
void ModuleEntryTable::load_archived_entries(ClassLoaderData* loader_data,
Array<ModuleEntry*>* archived_modules) {
assert(UseSharedSpaces, "runtime only");
for (int i = 0; i < archived_modules->length(); i++) {
ModuleEntry* archived_entry = archived_modules->at(i);
archived_entry->load_from_archive(loader_data);
unsigned int hash = compute_hash(archived_entry->name());
archived_entry->set_hash(hash);
add_entry(hash_to_index(hash), archived_entry);
}
}
void ModuleEntryTable::restore_archived_oops(ClassLoaderData* loader_data, Array<ModuleEntry*>* archived_modules) {
assert(UseSharedSpaces, "runtime only");
for (int i = 0; i < archived_modules->length(); i++) {
ModuleEntry* archived_entry = archived_modules->at(i);
archived_entry->restore_archive_oops(loader_data);
}
}
#endif // INCLUDE_CDS_JAVA_HEAP
ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle,
bool is_open, Symbol* name,
Symbol* version, Symbol* location,

View File

@ -47,6 +47,8 @@
#define JAVA_BASE_NAME "java.base"
#define JAVA_BASE_NAME_LEN 9
template <class T> class Array;
class MetaspaceClosure;
class ModuleClosure;
// A ModuleEntry describes a module that has been defined by a call to JVM_DefineModule.
@ -63,7 +65,7 @@ class ModuleClosure;
class ModuleEntry : public HashtableEntry<Symbol*, mtModule> {
private:
OopHandle _module; // java.lang.Module
OopHandle _pd; // java.security.ProtectionDomain, cached
OopHandle _shared_pd; // java.security.ProtectionDomain, cached
// for shared classes from this module
ClassLoaderData* _loader_data;
GrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module
@ -75,13 +77,15 @@ private:
bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules
bool _is_open; // whether the packages in the module are all unqualifiedly exported
bool _is_patched; // whether the module is patched via --patch-module
CDS_JAVA_HEAP_ONLY(narrowOop _archived_module_narrow_oop;)
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read.
public:
void init() {
_module = OopHandle();
_pd = OopHandle();
_shared_pd = OopHandle();
_loader_data = NULL;
_reads = NULL;
_version = NULL;
@ -188,6 +192,18 @@ public:
CDS_ONLY(int shared_path_index() { return _shared_path_index;})
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
#if INCLUDE_CDS_JAVA_HEAP
void iterate_symbols(MetaspaceClosure* closure);
ModuleEntry* allocate_archived_entry() const;
void init_as_archived_entry();
void init_archived_oops();
static ModuleEntry* get_archived_entry(ModuleEntry* orig_entry);
static Array<ModuleEntry*>* write_growable_array(GrowableArray<ModuleEntry*>* array);
static GrowableArray<ModuleEntry*>* restore_growable_array(Array<ModuleEntry*>* archived_array);
void load_from_archive(ClassLoaderData* loader_data);
void restore_archive_oops(ClassLoaderData* loader_data);
#endif
};
// Iterator interface
@ -270,6 +286,17 @@ public:
void print(outputStream* st = tty);
void verify();
#if INCLUDE_CDS_JAVA_HEAP
void iterate_symbols(MetaspaceClosure* closure);
Array<ModuleEntry*>* allocate_archived_entries();
void init_archived_entries(Array<ModuleEntry*>* archived_modules);
void init_archived_oops(Array<ModuleEntry*>* archived_modules);
void load_archived_entries(ClassLoaderData* loader_data,
Array<ModuleEntry*>* archived_modules);
void restore_archived_oops(ClassLoaderData* loader_data,
Array<ModuleEntry*>* archived_modules);
#endif
};
#endif // SHARE_CLASSFILE_MODULEENTRY_HPP

View File

@ -27,6 +27,7 @@
#include "classfile/classFileParser.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/javaAssertions.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/javaClasses.inline.hpp"
@ -39,7 +40,9 @@
#include "classfile/vmSymbols.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.inline.hpp"
@ -268,6 +271,7 @@ void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRA
void Modules::define_module(jobject module, jboolean is_open, jstring version,
jstring location, jobjectArray packages, TRAPS) {
check_cds_restrictions(CHECK);
ResourceMark rm(THREAD);
if (module == NULL) {
@ -450,6 +454,46 @@ void Modules::define_module(jobject module, jboolean is_open, jstring version,
}
}
#if INCLUDE_CDS_JAVA_HEAP
void Modules::define_archived_modules(jobject platform_loader, jobject system_loader, TRAPS) {
assert(UseSharedSpaces && MetaspaceShared::use_full_module_graph(), "must be");
// We don't want the classes used by the archived full module graph to be redefined by JVMTI.
// Luckily, such classes are loaded in the JVMTI "early" phase, and CDS is disabled if a JVMTI
// agent wants to redefine classes in this phase.
JVMTI_ONLY(assert(JvmtiExport::is_early_phase(), "must be"));
assert(!(JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()),
"CDS should be disabled if early class hooks are enabled");
Handle java_base_module(THREAD, ClassLoaderDataShared::restore_archived_oops_for_null_class_loader_data());
// Patch any previously loaded class's module field with java.base's java.lang.Module.
ModuleEntryTable::patch_javabase_entries(java_base_module);
if (platform_loader == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null platform loader object");
}
if (system_loader == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null system loader object");
}
Handle h_platform_loader(THREAD, JNIHandles::resolve_non_null(platform_loader));
ClassLoaderData* platform_loader_data = SystemDictionary::register_loader(h_platform_loader);
ClassLoaderDataShared::restore_java_platform_loader_from_archive(platform_loader_data);
Handle h_system_loader(THREAD, JNIHandles::resolve_non_null(system_loader));
ClassLoaderData* system_loader_data = SystemDictionary::register_loader(h_system_loader);
ClassLoaderDataShared::restore_java_system_loader_from_archive(system_loader_data);
}
void Modules::check_cds_restrictions(TRAPS) {
if (DumpSharedSpaces && Universe::is_module_initialized() && MetaspaceShared::use_full_module_graph()) {
THROW_MSG(vmSymbols::java_lang_UnsupportedOperationException(),
"During -Xshare:dump, module system cannot be modified after it's initialized");
}
}
#endif // INCLUDE_CDS_JAVA_HEAP
void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) {
ResourceMark rm(THREAD);
@ -488,6 +532,7 @@ void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) {
}
void Modules::add_module_exports(jobject from_module, jstring package_name, jobject to_module, TRAPS) {
check_cds_restrictions(CHECK);
if (package_name == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
@ -555,6 +600,7 @@ void Modules::add_module_exports(jobject from_module, jstring package_name, jobj
void Modules::add_module_exports_qualified(jobject from_module, jstring package,
jobject to_module, TRAPS) {
check_cds_restrictions(CHECK);
if (to_module == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"to_module is null");
@ -563,6 +609,7 @@ void Modules::add_module_exports_qualified(jobject from_module, jstring package,
}
void Modules::add_reads_module(jobject from_module, jobject to_module, TRAPS) {
check_cds_restrictions(CHECK);
if (from_module == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"from_module is null");
@ -668,6 +715,7 @@ jobject Modules::get_named_module(Handle h_loader, const char* package_name, TRA
// Export package in module to all unnamed modules.
void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package_name, TRAPS) {
check_cds_restrictions(CHECK);
if (module == NULL) {
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
"module is null");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -32,6 +32,7 @@ class ModuleEntryTable;
class Symbol;
class Modules : AllStatic {
static void check_cds_restrictions(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
public:
// define_module defines a module containing the specified packages. It binds the
@ -52,6 +53,9 @@ public:
static void define_module(jobject module, jboolean is_open, jstring version,
jstring location, jobjectArray packages, TRAPS);
static void define_archived_modules(jobject platform_loader, jobject system_loader,
TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
// Provides the java.lang.Module for the unnamed module defined
// to the boot loader.
//

View File

@ -26,7 +26,11 @@
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
#include "logging/log.hpp"
#include "memory/archiveBuilder.hpp"
#include "memory/archiveUtils.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "oops/array.hpp"
#include "oops/symbol.hpp"
#include "runtime/java.hpp"
#include "runtime/handles.inline.hpp"
@ -34,6 +38,8 @@
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/ostream.hpp"
#include "utilities/quickSort.hpp"
#include "utilities/resourceHash.hpp"
// Returns true if this package specifies m as a qualified export, including through an unnamed export
bool PackageEntry::is_qexported_to(ModuleEntry* m) const {
@ -189,6 +195,126 @@ PackageEntryTable::~PackageEntryTable() {
assert(new_entry_free_list() == NULL, "entry present on PackageEntryTable's free list");
}
#if INCLUDE_CDS_JAVA_HEAP
typedef ResourceHashtable<
const PackageEntry*,
PackageEntry*,
primitive_hash<const PackageEntry*>,
primitive_equals<const PackageEntry*>,
557, // prime number
ResourceObj::C_HEAP> ArchivedPackageEntries;
static ArchivedPackageEntries* _archived_packages_entries = NULL;
PackageEntry* PackageEntry::allocate_archived_entry() const {
assert(!in_unnamed_module(), "unnamed packages/modules are not archived");
PackageEntry* archived_entry = (PackageEntry*)MetaspaceShared::read_write_space_alloc(sizeof(PackageEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(PackageEntry));
if (_archived_packages_entries == NULL) {
_archived_packages_entries = new (ResourceObj::C_HEAP, mtClass)ArchivedPackageEntries();
}
assert(_archived_packages_entries->get(this) == NULL, "Each PackageEntry must not be shared across PackageEntryTables");
_archived_packages_entries->put(this, archived_entry);
return archived_entry;
}
PackageEntry* PackageEntry::get_archived_entry(PackageEntry* orig_entry) {
PackageEntry** ptr = _archived_packages_entries->get(orig_entry);
assert(ptr != NULL && *ptr != NULL, "must have been allocated");
return *ptr;
}
void PackageEntry::iterate_symbols(MetaspaceClosure* closure) {
closure->push(literal_addr()); // name
}
void PackageEntry::init_as_archived_entry() {
Array<ModuleEntry*>* archived_qualified_exports = ModuleEntry::write_growable_array(_qualified_exports);
set_next(NULL);
set_literal(ArchiveBuilder::get_relocated_symbol(literal()));
set_hash(0x0); // re-init at runtime
_module = ModuleEntry::get_archived_entry(_module);
_qualified_exports = (GrowableArray<ModuleEntry*>*)archived_qualified_exports;
_defined_by_cds_in_class_path = 0;
ArchivePtrMarker::mark_pointer((address*)literal_addr());
ArchivePtrMarker::mark_pointer((address*)&_module);
ArchivePtrMarker::mark_pointer((address*)&_qualified_exports);
}
void PackageEntry::load_from_archive() {
_qualified_exports = ModuleEntry::restore_growable_array((Array<ModuleEntry*>*)_qualified_exports);
JFR_ONLY(INIT_ID(this);)
}
static int compare_package_by_name(PackageEntry* a, PackageEntry* b) {
assert(a == b || a->name() != b->name(), "no duplicated names");
return a->name()->fast_compare(b->name());
}
void PackageEntryTable::iterate_symbols(MetaspaceClosure* closure) {
for (int i = 0; i < table_size(); ++i) {
for (PackageEntry* p = bucket(i); p != NULL; p = p->next()) {
p->iterate_symbols(closure);
}
}
}
Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
// First count the packages in named modules
int n, i;
for (n = 0, i = 0; i < table_size(); ++i) {
for (PackageEntry* p = bucket(i); p != NULL; p = p->next()) {
if (p->module()->name() != NULL) {
n++;
}
}
}
Array<PackageEntry*>* archived_packages = MetaspaceShared::new_rw_array<PackageEntry*>(n);
for (n = 0, i = 0; i < table_size(); ++i) {
for (PackageEntry* p = bucket(i); p != NULL; p = p->next()) {
if (p->module()->name() != NULL) {
// We don't archive unnamed modules, or packages in unnamed modules. They will be
// created on-demand at runtime as classes in such packages are loaded.
archived_packages->at_put(n++, p);
}
}
}
if (n > 1) {
QuickSort::sort(archived_packages->data(), n, (_sort_Fn)compare_package_by_name, true);
}
for (i = 0; i < n; i++) {
archived_packages->at_put(i, archived_packages->at(i)->allocate_archived_entry());
ArchivePtrMarker::mark_pointer((address*)archived_packages->adr_at(i));
}
return archived_packages;
}
void PackageEntryTable::init_archived_entries(Array<PackageEntry*>* archived_packages) {
for (int i = 0; i < archived_packages->length(); i++) {
PackageEntry* archived_entry = archived_packages->at(i);
archived_entry->init_as_archived_entry();
}
}
void PackageEntryTable::load_archived_entries(Array<PackageEntry*>* archived_packages) {
assert(UseSharedSpaces, "runtime only");
for (int i = 0; i < archived_packages->length(); i++) {
PackageEntry* archived_entry = archived_packages->at(i);
archived_entry->load_from_archive();
unsigned int hash = compute_hash(archived_entry->name());
archived_entry->set_hash(hash);
add_entry(hash_to_index(hash), archived_entry);
}
}
#endif // INCLUDE_CDS_JAVA_HEAP
PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, ModuleEntry* module) {
assert(Module_lock->owned_by_self(), "should have the Module_lock");
PackageEntry* entry = (PackageEntry*)Hashtable<Symbol*, mtModule>::allocate_new_entry(hash, name);
@ -274,7 +400,6 @@ void PackageEntryTable::verify_javabase_packages(GrowableArray<Symbol*> *pkg_lis
}
}
}
}
// iteration of qualified exports

View File

@ -36,6 +36,8 @@
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
template <class T> class Array;
class MetaspaceClosure;
// A PackageEntry basically represents a Java package. It contains:
// - Symbol* containing the package's name.
@ -217,6 +219,14 @@ public:
void print(outputStream* st = tty);
void verify();
#if INCLUDE_CDS_JAVA_HEAP
void iterate_symbols(MetaspaceClosure* closure);
PackageEntry* allocate_archived_entry() const;
void init_as_archived_entry();
static PackageEntry* get_archived_entry(PackageEntry* orig_entry);
void load_from_archive();
#endif
static int max_index_for_defined_in_class_path() {
return sizeof(int) * BitsPerByte;
}
@ -295,6 +305,13 @@ public:
void print(outputStream* st = tty);
void verify();
#if INCLUDE_CDS_JAVA_HEAP
void iterate_symbols(MetaspaceClosure* closure);
Array<PackageEntry*>* allocate_archived_entries();
void init_archived_entries(Array<PackageEntry*>* archived_packages);
void load_archived_entries(Array<PackageEntry*>* archived_packages);
#endif
};
#endif // SHARE_CLASSFILE_PACKAGEENTRY_HPP

View File

@ -187,10 +187,13 @@ class TableStatistics;
do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream ) \
do_klass(URL_klass, java_net_URL ) \
do_klass(Jar_Manifest_klass, java_util_jar_Manifest ) \
do_klass(jdk_internal_loader_BuiltinClassLoader_klass,jdk_internal_loader_BuiltinClassLoader ) \
do_klass(jdk_internal_loader_ClassLoaders_klass, jdk_internal_loader_ClassLoaders ) \
do_klass(jdk_internal_loader_ClassLoaders_AppClassLoader_klass, jdk_internal_loader_ClassLoaders_AppClassLoader) \
do_klass(jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass, jdk_internal_loader_ClassLoaders_PlatformClassLoader) \
do_klass(CodeSource_klass, java_security_CodeSource ) \
do_klass(ConcurrentHashMap_klass, java_util_concurrent_ConcurrentHashMap ) \
do_klass(ArrayList_klass, java_util_ArrayList ) \
\
do_klass(StackTraceElement_klass, java_lang_StackTraceElement ) \
\

View File

@ -130,6 +130,7 @@
template(java_lang_Record, "java/lang/Record") \
\
template(jdk_internal_loader_NativeLibraries, "jdk/internal/loader/NativeLibraries") \
template(jdk_internal_loader_BuiltinClassLoader, "jdk/internal/loader/BuiltinClassLoader") \
template(jdk_internal_loader_ClassLoaders_AppClassLoader, "jdk/internal/loader/ClassLoaders$AppClassLoader") \
template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
\
@ -664,6 +665,8 @@
\
/* cds */ \
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
template(java_util_concurrent_ConcurrentHashMap, "java/util/concurrent/ConcurrentHashMap") \
template(java_util_ArrayList, "java/util/ArrayList") \
template(toFileURL_name, "toFileURL") \
template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \
template(url_void_signature, "(Ljava/net/URL;)V") \

View File

@ -490,6 +490,14 @@ JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package);
JNIEXPORT void JNICALL
JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module);
/*
* Define all modules that have been stored in the CDS archived heap.
* platform_loader: the built-in platform class loader
* system_loader: the built-in system class loader
*/
JNIEXPORT void JNICALL
JVM_DefineArchivedModules(JNIEnv *env, jobject platform_loader, jobject system_loader);
/*
* Reflection support functions
*/

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "logging/log.hpp"
#include "logging/logMessage.hpp"
@ -218,6 +219,11 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
log_info(cds)("Gathering classes and symbols ... ");
GatherKlassesAndSymbols doit(this);
iterate_roots(&doit, /*is_relocating_pointers=*/false);
#if INCLUDE_CDS_JAVA_HEAP
if (DumpSharedSpaces && MetaspaceShared::use_full_module_graph()) {
ClassLoaderDataShared::iterate_symbols(&doit);
}
#endif
doit.finish();
log_info(cds)("Number of classes %d", _num_instance_klasses + _num_obj_array_klasses + _num_type_array_klasses);

View File

@ -39,6 +39,7 @@ public:
f(SymbolBucket) \
f(StringHashentry) \
f(StringBucket) \
f(ModulesNatives) \
f(Other)
enum Type {
@ -74,6 +75,11 @@ public:
_bytes [which][type] += byte_size;
}
void record_modules(int byte_size, bool read_only) {
int which = (read_only) ? RO : RW;
_bytes [which][ModulesNativesType] += byte_size;
}
void record_other_type(int byte_size, bool read_only) {
int which = (read_only) ? RO : RW;
_bytes [which][OtherType] += byte_size;

View File

@ -218,6 +218,7 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
_max_heap_size = MaxHeapSize;
_narrow_klass_shift = CompressedKlassPointers::shift();
_use_optimized_module_handling = MetaspaceShared::use_optimized_module_handling();
_use_full_module_graph = MetaspaceShared::use_full_module_graph();
// The following fields are for sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@ -2179,7 +2180,12 @@ bool FileMapHeader::validate() {
if (!_use_optimized_module_handling) {
MetaspaceShared::disable_optimized_module_handling();
log_info(cds)("use_optimized_module_handling disabled: archive was created without optimized module handling");
log_info(cds)("optimized module handling: disabled because archive was created without optimized module handling");
}
if (!_use_full_module_graph) {
MetaspaceShared::disable_full_module_graph();
log_info(cds)("full module graph: disabled because archive was created without full module graph");
}
return true;

View File

@ -233,6 +233,7 @@ class FileMapHeader: private CDSFileMapHeaderBase {
bool _allow_archiving_with_java_agent; // setting of the AllowArchivingWithJavaAgent option
bool _use_optimized_module_handling;// No module-relation VM options were specified, so we can skip
// some expensive operations.
bool _use_full_module_graph; // Can we use the full archived module graph?
size_t _ptrmap_size_in_bits; // Size of pointer relocation bitmap
char* from_mapped_offset(size_t offset) const {

View File

@ -23,9 +23,13 @@
*/
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/gcLocker.hpp"
@ -45,6 +49,7 @@
#include "oops/fieldStreams.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "utilities/bitMap.inline.hpp"
#if INCLUDE_G1GC
@ -68,26 +73,35 @@ DumpedInternedStrings *HeapShared::_dumped_interned_strings = NULL;
// region. Warning: Objects in the subgraphs should not have reference fields
// assigned at runtime.
static ArchivableStaticFieldInfo closed_archive_subgraph_entry_fields[] = {
{"java/lang/Integer$IntegerCache", "archivedCache"},
{"java/lang/Long$LongCache", "archivedCache"},
{"java/lang/Byte$ByteCache", "archivedCache"},
{"java/lang/Short$ShortCache", "archivedCache"},
{"java/lang/Character$CharacterCache", "archivedCache"},
{"java/util/jar/Attributes$Name", "KNOWN_NAMES"},
{"sun/util/locale/BaseLocale", "constantBaseLocales"},
{"java/lang/Integer$IntegerCache", "archivedCache"},
{"java/lang/Long$LongCache", "archivedCache"},
{"java/lang/Byte$ByteCache", "archivedCache"},
{"java/lang/Short$ShortCache", "archivedCache"},
{"java/lang/Character$CharacterCache", "archivedCache"},
{"java/util/jar/Attributes$Name", "KNOWN_NAMES"},
{"sun/util/locale/BaseLocale", "constantBaseLocales"},
};
// Entry fields for subgraphs archived in the open archive heap region.
static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = {
{"jdk/internal/module/ArchivedModuleGraph", "archivedModuleGraph"},
{"java/util/ImmutableCollections", "archivedObjects"},
{"java/lang/module/Configuration", "EMPTY_CONFIGURATION"},
{"jdk/internal/math/FDBigInteger", "archivedCaches"},
{"jdk/internal/module/ArchivedModuleGraph", "archivedModuleGraph"},
{"java/util/ImmutableCollections", "archivedObjects"},
{"java/lang/module/Configuration", "EMPTY_CONFIGURATION"},
{"jdk/internal/math/FDBigInteger", "archivedCaches"},
};
// Entry fields for subgraphs archived in the open archive heap region (full module graph).
static ArchivableStaticFieldInfo fmg_open_archive_subgraph_entry_fields[] = {
{"jdk/internal/loader/ArchivedClassLoaders", "archivedClassLoaders"},
{"jdk/internal/module/ArchivedBootLayer", "archivedBootLayer"},
{"java/lang/Module$ArchivedData", "archivedData"},
};
const static int num_closed_archive_subgraph_entry_fields =
sizeof(closed_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
const static int num_open_archive_subgraph_entry_fields =
sizeof(open_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
const static int num_fmg_open_archive_subgraph_entry_fields =
sizeof(fmg_open_archive_subgraph_entry_fields) / sizeof(ArchivableStaticFieldInfo);
////////////////////////////////////////////////////////////////
//
@ -108,6 +122,36 @@ unsigned HeapShared::oop_hash(oop const& p) {
return hash;
}
static void reset_states(oop obj, TRAPS) {
Handle h_obj(THREAD, obj);
InstanceKlass* klass = InstanceKlass::cast(obj->klass());
TempNewSymbol method_name = SymbolTable::new_symbol("resetArchivedStates");
Symbol* method_sig = vmSymbols::void_method_signature();
while (klass != NULL) {
Method* method = klass->find_method(method_name, method_sig);
if (method != NULL) {
assert(method->is_private(), "must be");
if (log_is_enabled(Debug, cds)) {
ResourceMark rm(THREAD);
log_debug(cds)(" calling %s", method->name_and_sig_as_C_string());
}
JavaValue result(T_VOID);
JavaCalls::call_special(&result, h_obj, klass,
method_name, method_sig, CHECK);
}
klass = klass->java_super();
}
}
void HeapShared::reset_archived_object_states(TRAPS) {
assert(DumpSharedSpaces, "dump-time only");
log_debug(cds)("Resetting platform loader");
reset_states(SystemDictionary::java_platform_loader(), THREAD);
log_debug(cds)("Resetting system loader");
reset_states(SystemDictionary::java_system_loader(), THREAD);
}
HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = NULL;
oop HeapShared::find_archived_heap_object(oop obj) {
assert(DumpSharedSpaces, "dump-time only");
@ -238,6 +282,10 @@ void HeapShared::archive_java_heap_objects(GrowableArray<MemRegion> *closed,
log_info(cds)("Dumping objects to open archive heap region ...");
copy_open_archive_heap_objects(open);
if (MetaspaceShared::use_full_module_graph()) {
ClassLoaderDataShared::init_archived_oops();
}
destroy_archived_object_cache();
}
@ -256,7 +304,9 @@ void HeapShared::copy_closed_archive_heap_objects(
archive_object_subgraphs(closed_archive_subgraph_entry_fields,
num_closed_archive_subgraph_entry_fields,
true /* is_closed_archive */, THREAD);
true /* is_closed_archive */,
false /* is_full_module_graph */,
THREAD);
G1CollectedHeap::heap()->end_archive_alloc_range(closed_archive,
os::vm_allocation_granularity());
@ -276,7 +326,15 @@ void HeapShared::copy_open_archive_heap_objects(
archive_object_subgraphs(open_archive_subgraph_entry_fields,
num_open_archive_subgraph_entry_fields,
false /* is_closed_archive */,
false /* is_full_module_graph */,
THREAD);
if (MetaspaceShared::use_full_module_graph()) {
archive_object_subgraphs(fmg_open_archive_subgraph_entry_fields,
num_fmg_open_archive_subgraph_entry_fields,
false /* is_closed_archive */,
true /* is_full_module_graph */,
THREAD);
}
G1CollectedHeap::heap()->end_archive_alloc_range(open_archive,
os::vm_allocation_granularity());
@ -296,15 +354,22 @@ HeapShared::RunTimeKlassSubGraphInfoTable HeapShared::_run_time_subgraph_info_
// Get the subgraph_info for Klass k. A new subgraph_info is created if
// there is no existing one for k. The subgraph_info records the relocated
// Klass* of the original k.
KlassSubGraphInfo* HeapShared::init_subgraph_info(Klass* k, bool is_full_module_graph) {
assert(DumpSharedSpaces, "dump time only");
bool created;
Klass* relocated_k = MetaspaceShared::get_relocated_klass(k);
KlassSubGraphInfo* info =
_dump_time_subgraph_info_table->put_if_absent(relocated_k, KlassSubGraphInfo(relocated_k, is_full_module_graph),
&created);
assert(created, "must not initialize twice");
return info;
}
KlassSubGraphInfo* HeapShared::get_subgraph_info(Klass* k) {
assert(DumpSharedSpaces, "dump time only");
Klass* relocated_k = MetaspaceShared::get_relocated_klass(k);
KlassSubGraphInfo* info = _dump_time_subgraph_info_table->get(relocated_k);
if (info == NULL) {
_dump_time_subgraph_info_table->put(relocated_k, KlassSubGraphInfo(relocated_k));
info = _dump_time_subgraph_info_table->get(relocated_k);
++ _dump_time_subgraph_info_table->_count;
}
assert(info != NULL, "must have been initialized");
return info;
}
@ -384,6 +449,7 @@ void ArchivedKlassSubGraphInfoRecord::init(KlassSubGraphInfo* info) {
_k = info->klass();
_entry_field_records = NULL;
_subgraph_object_klasses = NULL;
_is_full_module_graph = info->is_full_module_graph();
// populate the entry fields
GrowableArray<juint>* entry_fields = info->subgraph_entry_fields();
@ -464,7 +530,7 @@ void HeapShared::serialize_subgraph_info_table_header(SerializeClosure* soc) {
_run_time_subgraph_info_table.serialize_header(soc);
}
void HeapShared::initialize_from_archived_subgraph(Klass* k) {
void HeapShared::initialize_from_archived_subgraph(Klass* k, TRAPS) {
if (!open_archive_heap_region_mapped()) {
return; // nothing to do
}
@ -476,7 +542,9 @@ void HeapShared::initialize_from_archived_subgraph(Klass* k) {
// Initialize from archived data. Currently this is done only
// during VM initialization time. No lock is needed.
if (record != NULL) {
Thread* THREAD = Thread::current();
if (record->is_full_module_graph() && !MetaspaceShared::use_full_module_graph()) {
return;
}
int i;
// Load/link/initialize the klasses of the objects in the subgraph.
@ -628,6 +696,25 @@ void HeapShared::check_closed_archive_heap_region_object(InstanceKlass* k,
}
}
void HeapShared::check_module_oop(oop orig_module_obj) {
assert(DumpSharedSpaces, "must be");
assert(java_lang_Module::is_instance(orig_module_obj), "must be");
ModuleEntry* orig_module_ent = java_lang_Module::module_entry_raw(orig_module_obj);
if (orig_module_ent == NULL) {
// These special Module objects are created in Java code. They are not
// defined via Modules::define_module(), so they don't have a ModuleEntry:
// java.lang.Module::ALL_UNNAMED_MODULE
// java.lang.Module::EVERYONE_MODULE
// jdk.internal.loader.ClassLoaders$BootClassLoader::unnamedModule
assert(java_lang_Module::name(orig_module_obj) == NULL, "must be unnamed");
log_info(cds, heap)("Module oop with No ModuleEntry* @[" PTR_FORMAT "]", p2i(orig_module_obj));
} else {
ClassLoaderData* loader_data = orig_module_ent->loader_data();
assert(loader_data->is_builtin_class_loader_data(), "must be");
}
}
// (1) If orig_obj has not been archived yet, archive it.
// (2) If orig_obj has not been seen yet (since start_recording_subgraph() was called),
// trace all objects that are reachable from it, and make sure these objects are archived.
@ -695,6 +782,18 @@ oop HeapShared::archive_reachable_objects_from(int level,
vm_exit(1);
}
}
if (java_lang_Module::is_instance(orig_obj)) {
check_module_oop(orig_obj);
java_lang_Module::set_module_entry(archived_obj, NULL);
java_lang_Module::set_loader(archived_obj, NULL);
} else if (java_lang_ClassLoader::is_instance(orig_obj)) {
// class_data will be restored explicitly at run time.
guarantee(orig_obj == SystemDictionary::java_platform_loader() ||
orig_obj == SystemDictionary::java_system_loader() ||
java_lang_ClassLoader::loader_data_raw(orig_obj) == NULL, "must be");
java_lang_ClassLoader::release_set_loader_data(archived_obj, NULL);
}
}
assert(archived_obj != NULL, "must be");
@ -881,8 +980,9 @@ void HeapShared::set_has_been_seen_during_subgraph_recording(oop obj) {
++ _num_new_walked_objs;
}
void HeapShared::start_recording_subgraph(InstanceKlass *k, const char* class_name) {
void HeapShared::start_recording_subgraph(InstanceKlass *k, const char* class_name, bool is_full_module_graph) {
log_info(cds, heap)("Start recording subgraph(s) for archived fields in %s", class_name);
init_subgraph_info(k, is_full_module_graph);
init_seen_objects_table();
_num_new_walked_objs = 0;
_num_new_archived_objs = 0;
@ -959,6 +1059,11 @@ void HeapShared::init_subgraph_entry_fields(Thread* THREAD) {
init_subgraph_entry_fields(open_archive_subgraph_entry_fields,
num_open_archive_subgraph_entry_fields,
THREAD);
if (MetaspaceShared::use_full_module_graph()) {
init_subgraph_entry_fields(fmg_open_archive_subgraph_entry_fields,
num_fmg_open_archive_subgraph_entry_fields,
THREAD);
}
}
void HeapShared::init_for_dumping(Thread* THREAD) {
@ -968,6 +1073,7 @@ void HeapShared::init_for_dumping(Thread* THREAD) {
void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
int num, bool is_closed_archive,
bool is_full_module_graph,
Thread* THREAD) {
_num_total_subgraph_recordings = 0;
_num_total_walked_objs = 0;
@ -985,7 +1091,7 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
for (i = 0; i < num; ) {
ArchivableStaticFieldInfo* info = &fields[i];
const char* klass_name = info->klass_name;
start_recording_subgraph(info->klass, klass_name);
start_recording_subgraph(info->klass, klass_name, is_full_module_graph);
// If you have specified consecutive fields of the same klass in
// fields[], these will be archived in the same
@ -996,6 +1102,7 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
if (f->klass_name != klass_name) {
break;
}
archive_reachable_objects_from_static_field(f->klass, f->klass_name,
f->offset, f->field_name,
is_closed_archive, CHECK);

View File

@ -66,10 +66,12 @@ class KlassSubGraphInfo: public CHeapObj<mtClass> {
// is_closed_archive flag.
GrowableArray<juint>* _subgraph_entry_fields;
bool _is_full_module_graph;
public:
KlassSubGraphInfo(Klass* k) :
KlassSubGraphInfo(Klass* k, bool is_full_module_graph) :
_k(k), _subgraph_object_klasses(NULL),
_subgraph_entry_fields(NULL) {}
_subgraph_entry_fields(NULL),
_is_full_module_graph(is_full_module_graph) {}
~KlassSubGraphInfo() {
if (_subgraph_object_klasses != NULL) {
delete _subgraph_object_klasses;
@ -93,6 +95,7 @@ class KlassSubGraphInfo: public CHeapObj<mtClass> {
return _subgraph_object_klasses == NULL ? 0 :
_subgraph_object_klasses->length();
}
bool is_full_module_graph() const { return _is_full_module_graph; }
};
// An archived record of object sub-graphs reachable from static
@ -101,6 +104,7 @@ class KlassSubGraphInfo: public CHeapObj<mtClass> {
class ArchivedKlassSubGraphInfoRecord {
private:
Klass* _k;
bool _is_full_module_graph;
// contains pairs of field offset and value for each subgraph entry field
Array<juint>* _entry_field_records;
@ -115,6 +119,7 @@ class ArchivedKlassSubGraphInfoRecord {
Klass* klass() const { return _k; }
Array<juint>* entry_field_records() const { return _entry_field_records; }
Array<Klass*>* subgraph_object_klasses() const { return _subgraph_object_klasses; }
bool is_full_module_graph() const { return _is_full_module_graph; }
};
#endif // INCLUDE_CDS_JAVA_HEAP
@ -186,6 +191,7 @@ private:
static void archive_object_subgraphs(ArchivableStaticFieldInfo fields[],
int num,
bool is_closed_archive,
bool is_full_module_graph,
Thread* THREAD);
// Archive object sub-graph starting from the given static field
@ -200,6 +206,7 @@ private:
static void verify_reachable_objects_from(oop obj, bool is_archived) PRODUCT_RETURN;
static void verify_subgraph_from(oop orig_obj) PRODUCT_RETURN;
static KlassSubGraphInfo* init_subgraph_info(Klass *k, bool is_full_module_graph);
static KlassSubGraphInfo* get_subgraph_info(Klass *k);
static void init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
@ -239,13 +246,17 @@ private:
static int _num_total_recorded_klasses;
static int _num_total_verifications;
static void start_recording_subgraph(InstanceKlass *k, const char* klass_name);
static void start_recording_subgraph(InstanceKlass *k, const char* klass_name,
bool is_full_module_graph);
static void done_recording_subgraph(InstanceKlass *k, const char* klass_name);
static bool has_been_seen_during_subgraph_recording(oop obj);
static void set_has_been_seen_during_subgraph_recording(oop obj);
static void check_module_oop(oop orig_module_obj);
public:
static void reset_archived_object_states(TRAPS);
static void create_archived_object_cache() {
_archived_object_cache =
new (ResourceObj::C_HEAP, mtClass)ArchivedObjectCache();
@ -321,7 +332,7 @@ private:
inline static bool is_archived_object(oop p) NOT_CDS_JAVA_HEAP_RETURN_(false);
static void initialize_from_archived_subgraph(Klass* k) NOT_CDS_JAVA_HEAP_RETURN;
static void initialize_from_archived_subgraph(Klass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
// NarrowOops stored in the CDS archive may use a different encoding scheme
// than CompressedOops::{base,shift} -- see FileMapInfo::map_heap_regions_impl.

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/classListParser.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/loaderConstraints.hpp"
@ -40,6 +41,7 @@
#include "logging/logMessage.hpp"
#include "memory/archiveBuilder.hpp"
#include "memory/archiveUtils.inline.hpp"
#include "memory/dumpAllocStats.hpp"
#include "memory/dynamicArchive.hpp"
#include "memory/filemap.hpp"
#include "memory/heapShared.inline.hpp"
@ -87,6 +89,7 @@ void* MetaspaceShared::_shared_metaspace_static_top = NULL;
intx MetaspaceShared::_relocation_delta;
char* MetaspaceShared::_requested_base_address;
bool MetaspaceShared::_use_optimized_module_handling = true;
bool MetaspaceShared::_use_full_module_graph = true;
// The CDS archive is divided into the following regions:
// mc - misc code (the method entry trampolines, c++ vtables)
@ -151,6 +154,10 @@ char* MetaspaceShared::read_only_space_alloc(size_t num_bytes) {
return _ro_region.allocate(num_bytes);
}
char* MetaspaceShared::read_write_space_alloc(size_t num_bytes) {
return _rw_region.allocate(num_bytes);
}
size_t MetaspaceShared::reserved_space_alignment() { return os::vm_allocation_granularity(); }
static bool shared_base_valid(char* shared_base) {
@ -500,6 +507,8 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
serialize_cloned_cpp_vtptrs(soc);
soc->do_tag(--tag);
CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc));
soc->do_tag(666);
}
@ -1070,10 +1079,29 @@ void VM_PopulateDumpSharedSpace::doit() {
char* cloned_vtables = _mc_region.top();
MetaspaceShared::allocate_cpp_vtable_clones();
_mc_region.pack(&_rw_region);
builder.dump_rw_region();
_rw_region.pack(&_ro_region);
builder.dump_ro_region();
{
_mc_region.pack(&_rw_region);
builder.dump_rw_region();
#if INCLUDE_CDS_JAVA_HEAP
if (MetaspaceShared::use_full_module_graph()) {
// Archive the ModuleEntry's and PackageEntry's of the 3 built-in loaders
char* start = _rw_region.top();
ClassLoaderDataShared::allocate_archived_tables();
ArchiveBuilder::alloc_stats()->record_modules(_rw_region.top() - start, /*read_only*/false);
}
#endif
}
{
_rw_region.pack(&_ro_region);
builder.dump_ro_region();
#if INCLUDE_CDS_JAVA_HEAP
if (MetaspaceShared::use_full_module_graph()) {
char* start = _ro_region.top();
ClassLoaderDataShared::init_archived_tables();
ArchiveBuilder::alloc_stats()->record_modules(_ro_region.top() - start, /*read_only*/true);
}
#endif
}
builder.relocate_pointers();
dump_shared_symbol_table(builder.symbols());
@ -1366,6 +1394,12 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
link_and_cleanup_shared_classes(CATCH);
log_info(cds)("Rewriting and linking classes: done");
#if INCLUDE_CDS_JAVA_HEAP
if (use_full_module_graph()) {
HeapShared::reset_archived_object_states(THREAD);
}
#endif
VM_PopulateDumpSharedSpace op;
MutexLocker ml(THREAD, HeapShared::is_heap_object_archiving_allowed() ?
Heap_lock : NULL); // needed by HeapShared::run_gc()
@ -1749,7 +1783,8 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
static_mapinfo->map_heap_regions();
}
});
log_info(cds)("Using optimized module handling %s", MetaspaceShared::use_optimized_module_handling() ? "enabled" : "disabled");
log_info(cds)("optimized module handling: %s", MetaspaceShared::use_optimized_module_handling() ? "enabled" : "disabled");
log_info(cds)("full module graph: %s", MetaspaceShared::use_full_module_graph() ? "enabled" : "disabled");
} else {
unmap_archive(static_mapinfo);
unmap_archive(dynamic_mapinfo);
@ -2074,6 +2109,17 @@ intx MetaspaceShared::final_delta() {
- intx(SharedBaseAddress); // .. but the base archive is mapped at here at dump time
}
bool MetaspaceShared::use_full_module_graph() {
bool result = _use_optimized_module_handling && _use_full_module_graph &&
(UseSharedSpaces || DumpSharedSpaces) && HeapShared::is_heap_object_archiving_allowed();
if (result && UseSharedSpaces) {
// Classes used by the archived full module graph are loaded in JVMTI early phase.
assert(!(JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()),
"CDS should be disabled if early class hooks are enabled");
}
return result;
}
void MetaspaceShared::print_on(outputStream* st) {
if (UseSharedSpaces || DumpSharedSpaces) {
st->print("CDS archive(s) mapped at: ");

View File

@ -78,6 +78,7 @@ class MetaspaceShared : AllStatic {
static intx _relocation_delta;
static char* _requested_base_address;
static bool _use_optimized_module_handling;
static bool _use_full_module_graph;
public:
enum {
// core archive spaces
@ -215,17 +216,22 @@ class MetaspaceShared : AllStatic {
// Allocate a block of memory from the "mc" or "ro" regions.
static char* misc_code_space_alloc(size_t num_bytes);
static char* read_only_space_alloc(size_t num_bytes);
static char* read_write_space_alloc(size_t num_bytes);
template <typename T>
static Array<T>* new_ro_array(int length) {
#if INCLUDE_CDS
size_t byte_size = Array<T>::byte_sizeof(length, sizeof(T));
Array<T>* array = (Array<T>*)read_only_space_alloc(byte_size);
array->initialize(length);
return array;
#else
return NULL;
#endif
}
template <typename T>
static Array<T>* new_rw_array(int length) {
size_t byte_size = Array<T>::byte_sizeof(length, sizeof(T));
Array<T>* array = (Array<T>*)read_write_space_alloc(byte_size);
array->initialize(length);
return array;
}
template <typename T>
@ -270,9 +276,13 @@ class MetaspaceShared : AllStatic {
GrowableArray<ArchiveHeapOopmapInfo>* open_oopmaps);
// Can we skip some expensive operations related to modules?
static bool use_optimized_module_handling() { return _use_optimized_module_handling; }
static bool use_optimized_module_handling() { return NOT_CDS(false) CDS_ONLY(_use_optimized_module_handling); }
static void disable_optimized_module_handling() { _use_optimized_module_handling = false; }
// Can we use the full archived modue graph?
static bool use_full_module_graph() NOT_CDS_RETURN_(false);
static void disable_full_module_graph() { _use_full_module_graph = false; }
private:
#if INCLUDE_CDS
static void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region,

View File

@ -47,6 +47,7 @@
#include "logging/logMessage.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/archiveUtils.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"

View File

@ -1329,6 +1329,7 @@ public:
virtual void remove_unshareable_info();
virtual void remove_java_mirror();
void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, PackageEntry* pkg_entry, TRAPS);
void init_shared_package_entry();
// jvm support
jint compute_modifier_flags(TRAPS) const;

View File

@ -1227,6 +1227,11 @@ JVM_ENTRY (void, JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject so
Modules::add_reads_module(from_module, source_module, CHECK);
JVM_END
JVM_ENTRY(void, JVM_DefineArchivedModules(JNIEnv *env, jobject platform_loader, jobject system_loader))
JVMWrapper("JVM_DefineArchivedModules");
Modules::define_archived_modules(platform_loader, system_loader, CHECK);
JVM_END
// Reflection support //////////////////////////////////////////////////////////////////////////////
JVM_ENTRY(jstring, JVM_InitClassName(JNIEnv *env, jclass cls))
@ -3722,7 +3727,7 @@ JVM_ENTRY(void, JVM_InitializeFromArchive(JNIEnv* env, jclass cls))
JVMWrapper("JVM_InitializeFromArchive");
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve(cls));
assert(k->is_klass(), "just checking");
HeapShared::initialize_from_archived_subgraph(k);
HeapShared::initialize_from_archived_subgraph(k, THREAD);
JVM_END
JVM_ENTRY(void, JVM_RegisterLambdaProxyClassForArchiving(JNIEnv* env,

View File

@ -1459,7 +1459,14 @@ bool Arguments::add_property(const char* prop, PropertyWriteable writeable, Prop
if (is_internal_module_property(key) ||
strcmp(key, "jdk.module.main") == 0) {
MetaspaceShared::disable_optimized_module_handling();
log_info(cds)("Using optimized module handling disabled due to incompatible property: %s=%s", key, value);
log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
}
if (strcmp(key, "jdk.module.showModuleResolution") == 0 ||
strcmp(key, "jdk.module.illegalAccess") == 0 ||
strcmp(key, "jdk.module.validation") == 0 ||
strcmp(key, "java.system.class.loader") == 0) {
MetaspaceShared::disable_full_module_graph();
log_info(cds)("full module graph: disabled due to incompatible property: %s=%s", key, value);
}
#endif
@ -2508,7 +2515,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
Arguments::append_sysclasspath(tail);
#if INCLUDE_CDS
MetaspaceShared::disable_optimized_module_handling();
log_info(cds)("Using optimized module handling disabled due to bootclasspath was appended");
log_info(cds)("optimized module handling: disabled because bootclasspath was appended");
#endif
// -bootclasspath/p:
} else if (match_option(option, "-Xbootclasspath/p:", &tail)) {

View File

@ -2714,6 +2714,17 @@ public abstract class ClassLoader {
offset = unsafe.objectFieldOffset(k, name);
return unsafe.compareAndSetReference(this, offset, null, obj);
}
/**
* Called by the VM, during -Xshare:dump
*/
private void resetArchivedStates() {
parallelLockMap.clear();
packages.clear();
package2certs.clear();
classes.clear();
classLoaderValueMap = null;
}
}
/*

View File

@ -55,6 +55,7 @@ import java.util.stream.Stream;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.VM;
import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.module.ModuleLoaderMap;
import jdk.internal.module.ServicesCatalog;
@ -246,12 +247,55 @@ public final class Module implements AnnotatedElement {
// --
// special Module to mean "all unnamed modules"
private static final Module ALL_UNNAMED_MODULE = new Module(null);
private static final Set<Module> ALL_UNNAMED_MODULE_SET = Set.of(ALL_UNNAMED_MODULE);
private static final Module ALL_UNNAMED_MODULE;
private static final Set<Module> ALL_UNNAMED_MODULE_SET;
// special Module to mean "everyone"
private static final Module EVERYONE_MODULE = new Module(null);
private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE);
private static final Module EVERYONE_MODULE;
private static final Set<Module> EVERYONE_SET;
private static class ArchivedData {
private static ArchivedData archivedData;
private final Module allUnnamedModule;
private final Set<Module> allUnnamedModules;
private final Module everyoneModule;
private final Set<Module> everyoneSet;
private ArchivedData() {
this.allUnnamedModule = ALL_UNNAMED_MODULE;
this.allUnnamedModules = ALL_UNNAMED_MODULE_SET;
this.everyoneModule = EVERYONE_MODULE;
this.everyoneSet = EVERYONE_SET;
}
static void archive() {
archivedData = new ArchivedData();
}
static ArchivedData get() {
return archivedData;
}
static {
VM.initializeFromArchive(ArchivedData.class);
}
}
static {
ArchivedData archivedData = ArchivedData.get();
if (archivedData != null) {
ALL_UNNAMED_MODULE = archivedData.allUnnamedModule;
ALL_UNNAMED_MODULE_SET = archivedData.allUnnamedModules;
EVERYONE_MODULE = archivedData.everyoneModule;
EVERYONE_SET = archivedData.everyoneSet;
} else {
ALL_UNNAMED_MODULE = new Module(null);
ALL_UNNAMED_MODULE_SET = Set.of(ALL_UNNAMED_MODULE);
EVERYONE_MODULE = new Module(null);
EVERYONE_SET = Set.of(EVERYONE_MODULE);
ArchivedData.archive();
}
}
/**
* The holder of data structures to support readability, exports, and

View File

@ -2248,6 +2248,9 @@ public final class System {
public ServicesCatalog getServicesCatalog(ModuleLayer layer) {
return layer.getServicesCatalog();
}
public void bindToLoader(ModuleLayer layer, ClassLoader loader) {
layer.bindToLoader(loader);
}
public Stream<ModuleLayer> layers(ModuleLayer layer) {
return layer.layers();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -269,4 +269,11 @@ public class SecureClassLoader extends ClassLoader {
return cs.matchCerts(csk.cs, true);
}
}
/**
* Called by the VM, during -Xshare:dump
*/
private void resetArchivedStates() {
pdcache.clear();
}
}

View File

@ -256,6 +256,12 @@ public interface JavaLangAccess {
*/
ServicesCatalog getServicesCatalog(ModuleLayer layer);
/**
* Record that this layer has at least one module defined to the given
* class loader.
*/
void bindToLoader(ModuleLayer layer, ClassLoader loader);
/**
* Returns an ordered stream of layers. The first element is the
* given layer, the remaining elements are its parents, in DFS order.

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2020, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 jdk.internal.loader;
import java.util.Map;
import jdk.internal.misc.VM;
import jdk.internal.module.ServicesCatalog;
/**
* Used to archive the built-in class loaders, their services catalogs, and the
* package-to-module map used by the built-in class loaders.
*/
class ArchivedClassLoaders {
private static ArchivedClassLoaders archivedClassLoaders;
private final ClassLoader bootLoader;
private final ClassLoader platformLoader;
private final ClassLoader appLoader;
private final ServicesCatalog[] servicesCatalogs;
private final Map<String, ?> packageToModule;
private ArchivedClassLoaders() {
bootLoader = ClassLoaders.bootLoader();
platformLoader = ClassLoaders.platformClassLoader();
appLoader = ClassLoaders.appClassLoader();
servicesCatalogs = new ServicesCatalog[3];
servicesCatalogs[0] = BootLoader.getServicesCatalog();
servicesCatalogs[1] = ServicesCatalog.getServicesCatalog(platformLoader);
servicesCatalogs[2] = ServicesCatalog.getServicesCatalog(appLoader);
packageToModule = BuiltinClassLoader.packageToModule();
}
ClassLoader bootLoader() {
return bootLoader;
}
ClassLoader platformLoader() {
return platformLoader;
}
ClassLoader appLoader() {
return appLoader;
}
ServicesCatalog servicesCatalog(ClassLoader loader) {
if (loader == null) {
return servicesCatalogs[0];
} else if (loader == platformLoader) {
return servicesCatalogs[1];
} else if (loader == appLoader) {
return servicesCatalogs[2];
} else {
throw new InternalError();
}
}
Map<String, ?> packageToModule() {
return packageToModule;
}
static void archive() {
archivedClassLoaders = new ArchivedClassLoaders();
}
static ArchivedClassLoaders get() {
return archivedClassLoaders;
}
static {
VM.initializeFromArchive(ArchivedClassLoaders.class);
}
}

View File

@ -65,7 +65,15 @@ public class BootLoader {
}
// ServiceCatalog for the boot class loader
private static final ServicesCatalog SERVICES_CATALOG = ServicesCatalog.create();
private static final ServicesCatalog SERVICES_CATALOG;
static {
ArchivedClassLoaders archivedClassLoaders = ArchivedClassLoaders.get();
if (archivedClassLoaders != null) {
SERVICES_CATALOG = archivedClassLoaders.servicesCatalog(null);
} else {
SERVICES_CATALOG = ServicesCatalog.create();
}
}
// ClassLoaderValue map for the boot class loader
private static final ConcurrentHashMap<?, ?> CLASS_LOADER_VALUE_MAP

View File

@ -104,8 +104,7 @@ public class BuiltinClassLoader
private final BuiltinClassLoader parent;
// the URL class path, or null if there is no class path
private final URLClassPath ucp;
private @Stable URLClassPath ucp;
/**
* A module defined/loaded by a built-in class loader.
@ -156,10 +155,26 @@ public class BuiltinClassLoader
}
}
// maps package name to loaded module for modules in the boot layer
private static final Map<String, LoadedModule> packageToModule
= new ConcurrentHashMap<>(1024);
private static final Map<String, LoadedModule> packageToModule;
static {
ArchivedClassLoaders archivedClassLoaders = ArchivedClassLoaders.get();
if (archivedClassLoaders != null) {
@SuppressWarnings("unchecked")
Map<String, LoadedModule> map
= (Map<String, LoadedModule>) archivedClassLoaders.packageToModule();
packageToModule = map;
} else {
packageToModule = new ConcurrentHashMap<>(1024);
}
}
/**
* Invoked by ArchivedClassLoaders to archive the package-to-module map.
*/
static Map<String, ?> packageToModule() {
return packageToModule;
}
// maps a module name to a module reference
private final Map<String, ModuleReference> nameToModule;
@ -185,6 +200,21 @@ public class BuiltinClassLoader
this.moduleToReader = new ConcurrentHashMap<>();
}
/**
* Appends to the given file path to the class path.
*/
void appendClassPath(String path) {
// assert ucp != null;
ucp.addFile(path);
}
/**
* Sets the class path, called to reset the class path during -Xshare:dump
*/
void setClassPath(URLClassPath ucp) {
this.ucp = ucp;
}
/**
* Returns {@code true} if there is a class path associated with this
* class loader.
@ -1042,4 +1072,9 @@ public class BuiltinClassLoader
private static URL checkURL(URL url) {
return URLClassPath.checkURL(url);
}
// Called from VM only, during -Xshare:dump
private void resetArchivedStates() {
ucp = null;
}
}

View File

@ -36,6 +36,7 @@ import java.util.jar.Manifest;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.module.ServicesCatalog;
/**
* Creates and provides access to the built-in platform and application class
@ -56,14 +57,22 @@ public class ClassLoaders {
// Creates the built-in class loaders.
static {
// -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
String append = VM.getSavedProperty("jdk.boot.class.path.append");
BOOT_LOADER =
new BootClassLoader((append != null && !append.isEmpty())
? new URLClassPath(append, true)
: null);
PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER);
ArchivedClassLoaders archivedClassLoaders = ArchivedClassLoaders.get();
if (archivedClassLoaders != null) {
// assert VM.getSavedProperty("jdk.boot.class.path.append") == null
BOOT_LOADER = (BootClassLoader) archivedClassLoaders.bootLoader();
PLATFORM_LOADER = (PlatformClassLoader) archivedClassLoaders.platformLoader();
ServicesCatalog catalog = archivedClassLoaders.servicesCatalog(PLATFORM_LOADER);
ServicesCatalog.putServicesCatalog(PLATFORM_LOADER, catalog);
} else {
// -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
String append = VM.getSavedProperty("jdk.boot.class.path.append");
URLClassPath ucp = (append != null && !append.isEmpty())
? new URLClassPath(append, true)
: null;
BOOT_LOADER = new BootClassLoader(ucp);
PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER);
}
// A class path is required when no initial module is specified.
// In this case the class path defaults to "", meaning the current
// working directory. When an initial module is specified, on the
@ -75,7 +84,15 @@ public class ClassLoaders {
cp = (initialModuleName == null) ? "" : null;
}
URLClassPath ucp = new URLClassPath(cp, false);
APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp);
if (archivedClassLoaders != null) {
APP_LOADER = (AppClassLoader) archivedClassLoaders.appLoader();
ServicesCatalog catalog = archivedClassLoaders.servicesCatalog(APP_LOADER);
ServicesCatalog.putServicesCatalog(APP_LOADER, catalog);
APP_LOADER.setClassPath(ucp);
} else {
APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp);
ArchivedClassLoaders.archive();
}
}
/**
@ -144,11 +161,8 @@ public class ClassLoaders {
throw new InternalError();
}
final URLClassPath ucp;
AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) {
AppClassLoader(BuiltinClassLoader parent, URLClassPath ucp) {
super("app", parent, ucp);
this.ucp = ucp;
}
@Override
@ -181,7 +195,7 @@ public class ClassLoaders {
* @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
*/
void appendToClassPathForInstrumentation(String path) {
ucp.addFile(path);
appendClassPath(path);
}
/**
@ -190,6 +204,13 @@ public class ClassLoaders {
protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
return super.defineOrCheckPackage(pn, man, url);
}
/**
* Called by the VM, during -Xshare:dump
*/
private void resetArchivedStates() {
setClassPath(null);
}
}
/**

View File

@ -468,6 +468,8 @@ public class VM {
*/
public static native void initializeFromArchive(Class<?> c);
public static native void defineArchivedModules(ClassLoader platformLoader, ClassLoader systemLoader);
public static native long getRandomSeedForCDSDump();
/**

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2020, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 jdk.internal.module;
import jdk.internal.misc.VM;
/**
* Used by ModuleBootstrap for archiving the boot layer and the builder needed to
* set the IllegalAccessLogger.
*/
class ArchivedBootLayer {
private static ArchivedBootLayer archivedBootLayer;
private final ModuleLayer bootLayer;
private final IllegalAccessLogger.Builder builder;
private ArchivedBootLayer(ModuleLayer bootLayer,
IllegalAccessLogger.Builder builder) {
this.bootLayer = bootLayer;
this.builder = builder;
}
ModuleLayer bootLayer() {
return bootLayer;
}
IllegalAccessLogger.Builder illegalAccessLoggerBuilder() {
return builder;
}
static ArchivedBootLayer get() {
return archivedBootLayer;
}
static void archive(ModuleLayer layer, IllegalAccessLogger.Builder builder) {
archivedBootLayer = new ArchivedBootLayer(layer, builder);
}
static {
VM.initializeFromArchive(ArchivedBootLayer.class);
}
}

View File

@ -22,21 +22,20 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.module;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import jdk.internal.misc.VM;
/**
* Used by ModuleBootstrap to obtain the archived system modules and finder.
* Used by ModuleBootstrap for archiving the configuration for the boot layer,
* the system module finder, and the maps used to create the IllegalAccessLogger.
*/
final class ArchivedModuleGraph {
class ArchivedModuleGraph {
private static ArchivedModuleGraph archivedModuleGraph;
private final boolean hasSplitPackages;
@ -47,13 +46,13 @@ final class ArchivedModuleGraph {
private final Map<String, Set<String>> concealedPackagesToOpen;
private final Map<String, Set<String>> exportedPackagesToOpen;
public ArchivedModuleGraph(boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Function<String, ClassLoader> classLoaderFunction,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
private ArchivedModuleGraph(boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Function<String, ClassLoader> classLoaderFunction,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
this.hasSplitPackages = hasSplitPackages;
this.hasIncubatorModules = hasIncubatorModules;
this.finder = finder;
@ -107,8 +106,20 @@ final class ArchivedModuleGraph {
/**
* Archive the module graph for the given initial module.
*/
static void archive(ArchivedModuleGraph graph) {
archivedModuleGraph = graph;
static void archive(boolean hasSplitPackages,
boolean hasIncubatorModules,
ModuleFinder finder,
Configuration configuration,
Function<String, ClassLoader> classLoaderFunction,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen) {
archivedModuleGraph = new ArchivedModuleGraph(hasSplitPackages,
hasIncubatorModules,
finder,
configuration,
classLoaderFunction,
concealedPackagesToOpen,
exportedPackagesToOpen);
}
static {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -57,7 +57,7 @@ public final class IllegalAccessLogger {
/**
* Logger modes
*/
public static enum Mode {
public enum Mode {
/**
* Prints a warning when an illegal access succeeds and then
* discards the logger so that there is no further output.
@ -118,7 +118,7 @@ public final class IllegalAccessLogger {
}
/**
* Builds the IllegalAccessLogger and sets it as the system-wise logger.
* Builds the IllegalAccessLogger and sets it as the system-wide logger.
*/
public void complete() {
Map<Module, Set<String>> map1 = unmodifiableMap(moduleToConcealedPackages);

View File

@ -42,18 +42,19 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.JavaLangModuleAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.misc.VM;
import jdk.internal.perf.PerfCounter;
/**
@ -86,8 +87,8 @@ public final class ModuleBootstrap {
private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
// access to java.lang/module
private static final JavaLangModuleAccess JLMA
= SharedSecrets.getJavaLangModuleAccess();
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
// The ModulePatcher for the initial configuration
private static final ModulePatcher patcher = initModulePatcher();
@ -134,14 +135,58 @@ public final class ModuleBootstrap {
}
/**
* Initialize the module system, returning the boot layer.
* Returns true if the archived boot layer can be used. The system properties
* are checked in the order that they are used by boot2.
*/
private static boolean canUseArchivedBootLayer() {
return getProperty("jdk.module.upgrade.path") == null &&
getProperty("jdk.module.path") == null &&
getProperty("jdk.module.patch.0") == null && // --patch-module
getProperty("jdk.module.main") == null &&
getProperty("jdk.module.addmods.0") == null && // --add-modules
getProperty("jdk.module.limitmods") == null &&
getProperty("jdk.module.addreads.0") == null && // --add-reads
getProperty("jdk.module.addexports.0") == null && // --add-exports
getProperty("jdk.module.addopens.0") == null && // --add-opens
getProperty("jdk.module.illegalAccess") == null;
}
/**
* Initialize the module system, returning the boot layer. The boot layer
* is obtained from the CDS archive if possible, otherwise it is generated
* from the module graph.
*
* @see java.lang.System#initPhase2(boolean, boolean)
*/
public static ModuleLayer boot() throws Exception {
public static ModuleLayer boot() {
Counters.start();
ModuleLayer bootLayer;
ArchivedBootLayer archivedBootLayer = ArchivedBootLayer.get();
if (archivedBootLayer != null) {
assert canUseArchivedBootLayer();
bootLayer = archivedBootLayer.bootLayer();
BootLoader.getUnnamedModule(); // trigger <clinit> of BootLoader.
VM.defineArchivedModules(ClassLoaders.platformClassLoader(), ClassLoaders.appClassLoader());
// assume boot layer has at least one module providing a service
// that is mapped to the application class loader.
JLA.bindToLoader(bootLayer, ClassLoaders.appClassLoader());
// IllegalAccessLogger needs to be set
var illegalAccessLoggerBuilder = archivedBootLayer.illegalAccessLoggerBuilder();
if (illegalAccessLoggerBuilder != null) {
illegalAccessLoggerBuilder.complete();
}
} else {
bootLayer = boot2();
}
Counters.publish("jdk.module.boot.totalTime");
return bootLayer;
}
private static ModuleLayer boot2() {
// Step 0: Command line options
ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
@ -428,11 +473,12 @@ public final class ModuleBootstrap {
concealedPackagesToOpen = systemModules.concealedPackagesToOpen();
exportedPackagesToOpen = systemModules.exportedPackagesToOpen();
}
addIllegalAccess(upgradeModulePath,
concealedPackagesToOpen,
exportedPackagesToOpen,
bootLayer,
extraExportsOrOpens);
IllegalAccessLogger.Builder builder =
addIllegalAccess(upgradeModulePath,
concealedPackagesToOpen,
exportedPackagesToOpen,
bootLayer,
extraExportsOrOpens);
Counters.add("jdk.module.boot.7.adjustModulesTime");
// save module finders for later use
@ -442,21 +488,21 @@ public final class ModuleBootstrap {
limitedFinder = new SafeModuleFinder(finder);
}
// Module graph can be archived at CDS dump time. Only allow the
// unnamed module case for now.
// Archive module graph and boot layer can be archived at CDS dump time.
// Only allow the unnamed module case for now.
if (canArchive && (mainModule == null)) {
ArchivedModuleGraph.archive(
new ArchivedModuleGraph(hasSplitPackages,
hasIncubatorModules,
systemModuleFinder,
cf,
clf,
concealedPackagesToOpen,
exportedPackagesToOpen));
}
ArchivedModuleGraph.archive(hasSplitPackages,
hasIncubatorModules,
systemModuleFinder,
cf,
clf,
concealedPackagesToOpen,
exportedPackagesToOpen);
// total time to initialize
Counters.publish("jdk.module.boot.totalTime");
if (!hasSplitPackages && !hasIncubatorModules) {
ArchivedBootLayer.archive(bootLayer, builder);
}
}
return bootLayer;
}
@ -751,17 +797,18 @@ public final class ModuleBootstrap {
* Process the --illegal-access option (and its default) to open packages
* of system modules in the boot layer to code in unnamed modules.
*/
private static void addIllegalAccess(ModuleFinder upgradeModulePath,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen,
ModuleLayer bootLayer,
boolean extraExportsOrOpens) {
private static IllegalAccessLogger.Builder
addIllegalAccess(ModuleFinder upgradeModulePath,
Map<String, Set<String>> concealedPackagesToOpen,
Map<String, Set<String>> exportedPackagesToOpen,
ModuleLayer bootLayer,
boolean extraExportsOrOpens) {
String value = getAndRemoveProperty("jdk.module.illegalAccess");
IllegalAccessLogger.Mode mode = IllegalAccessLogger.Mode.ONESHOT;
if (value != null) {
switch (value) {
case "deny":
return;
return null;
case "permit":
break;
case "warn":
@ -773,7 +820,7 @@ public final class ModuleBootstrap {
default:
fail("Value specified to --illegal-access not recognized:"
+ " '" + value + "'");
return;
return null;
}
}
IllegalAccessLogger.Builder builder
@ -836,11 +883,11 @@ public final class ModuleBootstrap {
builder.logAccessToExportedPackages(m, exportedPackages);
// open the packages to unnamed modules
JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
jla.addOpensToAllUnnamed(m, concealedPackages, exportedPackages);
JLA.addOpensToAllUnnamed(m, concealedPackages, exportedPackages);
}
builder.complete();
return builder;
}
/**
@ -905,11 +952,19 @@ public final class ModuleBootstrap {
return decode(prefix, ",", true);
}
/**
* Gets the named system property
*/
private static String getProperty(String key) {
return System.getProperty(key);
}
/**
* Gets and remove the named system property
*/
private static String getAndRemoveProperty(String key) {
return (String)System.getProperties().remove(key);
return (String) System.getProperties().remove(key);
}
/**

View File

@ -171,6 +171,16 @@ public final class ServicesCatalog {
return catalog;
}
/**
* Associates the given ServicesCatalog with the given class loader.
*/
public static void putServicesCatalog(ClassLoader loader, ServicesCatalog catalog) {
ServicesCatalog previous = CLV.putIfAbsent(loader, catalog);
if (previous != null) {
throw new InternalError();
}
}
// the ServicesCatalog registered to a class loader
private static final ClassLoaderValue<ServicesCatalog> CLV = new ClassLoaderValue<>();
}

View File

@ -62,6 +62,13 @@ Java_jdk_internal_misc_VM_initializeFromArchive(JNIEnv *env, jclass ignore,
JVM_InitializeFromArchive(env, c);
}
JNIEXPORT void JNICALL
Java_jdk_internal_misc_VM_defineArchivedModules(JNIEnv *env, jclass ignore,
jobject platform_loader,
jobject system_loader) {
JVM_DefineArchivedModules(env, platform_loader, system_loader);
}
JNIEXPORT jlong JNICALL
Java_jdk_internal_misc_VM_getRandomSeedForCDSDump(JNIEnv *env, jclass ignore) {
return JVM_GetRandomSeedForCDSDump();

View File

@ -28,12 +28,15 @@
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
* @compile ../modules/CompilerUtils.java
* @run driver CheckForProperDetailStackTrace
*/
import jdk.test.lib.Platform;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -49,6 +52,11 @@ import java.util.regex.Pattern;
* through this test and update it accordingly.
*/
public class CheckForProperDetailStackTrace {
private static final String TEST_SRC = System.getProperty("test.src");
private static final String TEST_CLASSES = System.getProperty("test.classes");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods");
/* The stack trace we look for by default. Note that :: has been replaced by .*
to make sure it matches even if the symbol is not unmangled.
@ -83,11 +91,24 @@ public class CheckForProperDetailStackTrace {
private static String expectedSymbol = "locked_create_entry";
public static void main(String args[]) throws Exception {
boolean compiled;
// Compile module jdk.test declaration
compiled = CompilerUtils.compile(
SRC_DIR.resolve("jdk.test"),
MODS_DIR.resolve("jdk.test"));
if (!compiled) {
throw new RuntimeException("Test failed to compile module jdk.test");
}
// If modules in the system image have been archived in CDS, they will not be
// created again at run time. Explicitly use an external module to make sure
// we have a runtime-defined ModuleEntry
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:+UnlockDiagnosticVMOptions",
"-XX:NativeMemoryTracking=detail",
"-XX:+PrintNMTStatistics",
"-version");
"-p", MODS_DIR.toString(),
"-m", "jdk.test/test.Main");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020, 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.
*/
module jdk.test {
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020, 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 test;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("jdk.test/test/Main: hello");
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2020, 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.
*/
/**
* @test
* @bug 8244778
* @summary Make sure the archived mirrors of the primitive classes have the proper module (java.base)
* @requires vm.cds
* @library /test/lib
* @run driver PrimitiveClassMirrors
*/
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.process.OutputAnalyzer;
public class PrimitiveClassMirrors {
public static void main(String[] args) throws Exception {
CDSOptions opts = new CDSOptions();
CDSTestUtils.createArchiveAndCheck(opts);
opts.setUseVersion(false);
opts.addSuffix("-Xlog:cds=warning", "PrimitiveClassMirrors$TestApp");
OutputAnalyzer out = CDSTestUtils.runWithArchive(opts);
out.shouldHaveExitValue(0);
// The test should have same results if CDS is turned off
opts.setXShareMode("off");
OutputAnalyzer out2 = CDSTestUtils.runWithArchive(opts);
out2.shouldHaveExitValue(0);
}
static class TestApp {
public static void main(String args[]) throws Exception {
Class classes[] = {
int.class,
float.class,
double.class,
byte.class,
boolean.class,
char.class,
long.class,
short.class,
void.class,
int[].class,
float[].class,
double[].class,
byte[].class,
boolean[].class,
char[].class,
long[].class,
short[].class,
};
for (Class c : classes) {
test(c);
}
}
}
static void test(Class c) throws Exception {
Module m = c.getModule();
boolean unexpected = (m == null || !("java.base".equals(m.getName())));
System.out.println("Module for " + c + " = " + m + (unexpected ? " *** Error" : ""));
if (unexpected) {
throw new RuntimeException("Unexpected: " + m);
}
}
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2020, 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.
*/
/**
* @test
* @bug 8244778
* @summary Make sure that the ServicesCatalogs for boot/platform/app loaders are properly archived.
* @requires vm.cds
* @modules java.naming
* @library /test/lib
* @run driver ServiceLoaderTest
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.spi.ToolProvider;
import javax.naming.spi.InitialContextFactory;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.process.OutputAnalyzer;
public class ServiceLoaderTest {
public static void main(String[] args) throws Exception {
CDSOptions opts = new CDSOptions();
CDSTestUtils.createArchiveAndCheck(opts);
// Some mach5 tiers run with -vmoptions:-Xlog:cds=debug. This would cause the outputs to mismatch.
// Force -Xlog:cds=warning to supress the CDS logs.
opts.setUseVersion(false);
opts.addSuffix("-showversion", "-Xlog:cds=warning", "ServiceLoaderApp");
OutputAnalyzer out1 = CDSTestUtils.runWithArchive(opts);
opts.setXShareMode("off");
OutputAnalyzer out2 = CDSTestUtils.runWithArchive(opts);
compare(out1, out2);
}
static void compare(OutputAnalyzer out1, OutputAnalyzer out2) {
String[] arr1 = splitLines(out1);
String[] arr2 = splitLines(out2);
int max = arr1.length > arr2.length ? arr1.length : arr2.length;
for (int i = 0; i < max; i++) {
if (i >= arr1.length) {
mismatch(i, "<EOF>", arr2[i]);
}
if (i >= arr2.length) {
mismatch(i, arr1[i], "<EOF>");
}
if (!arr1[i].equals(arr2[i])) {
mismatch(i, arr1[i], arr2[i]);
}
}
}
static String[] splitLines(OutputAnalyzer out) {
return out.getStdout().split("\n");
}
static void mismatch(int i, String s1, String s2) {
System.out.println("Mismatched line: " + i);
System.out.println("cds on : " + s1);
System.out.println("cds off: " + s2);
throw new RuntimeException("Mismatched line " + i + ": \"" + s1 + "\" vs \"" + s2 + "\"");
}
}
class ServiceLoaderApp {
public static void main(String args[]) throws Exception {
doTest(ToolProvider.class);
doTest(InitialContextFactory.class);
}
static void doTest(Class c) throws Exception {
System.out.println("============================================================");
System.out.println("Testing : " + c.getName());
System.out.println("============================================================");
print_loader("default", ServiceLoader.load(c));
print_loader("null loader", ServiceLoader.load(c, null));
print_loader("platform loader", ServiceLoader.load(c, ServiceLoaderApp.class.getClassLoader().getParent()));
print_loader("system loader", ServiceLoader.load(c, ServiceLoaderApp.class.getClassLoader()));
}
static void print_loader(String testCase, ServiceLoader loader) throws Exception {
System.out.println("[TEST CASE] " + testCase);
System.out.println("[svcloader] " + asString(loader));
Iterator it = loader.iterator();
ArrayList<String> list = new ArrayList<>();
while (it.hasNext()) {
list.add(asString(it.next().toString()));
}
Collections.sort(list);
for (String s : list) {
System.out.println(s);
}
}
static String asString(Object o) {
String s = o.toString();
int n = s.indexOf("@");
if (n >= 0) {
s = s.substring(0, n);
}
return s;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -72,6 +72,7 @@ public class SpecifySysLoaderProp {
TestCommon.run(
"-verbose:class",
"-cp", appJar,
"-Xlog:cds",
"-Djava.system.class.loader=TestClassLoader",
"ReportMyLoader")
.assertNormalExit("ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@", //<-this is still printed because TestClassLoader simply delegates to Launcher$AppLoader, but ...
@ -80,6 +81,7 @@ public class SpecifySysLoaderProp {
.assertNormalExit(output -> {
output.shouldMatch(".class,load. TestClassLoader source: file:");
output.shouldMatch(".class,load. ReportMyLoader source: file:.*" + jarFileName);
output.shouldContain("full module graph: disabled due to incompatible property: java.system.class.loader=");
});
// (3) Try to change the java.system.class.loader programmatically after

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2020, 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.
*
*/
/**
* @test
* @bug 8244778
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @run driver NewModuleFinderTest
* @summary Make sure the archived module graph can co-exist with modules that are
* dynamically defined at runtime using the ModuleFinder API.
*/
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class NewModuleFinderTest {
private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
private static final String TEST_SRC = System.getProperty("test.src");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "modulepath/src");
private static final Path MODS_DIR = Paths.get("mods");
// the module name of the test module
private static final String TEST_MODULE = "com.simple";
// the module main class
private static final String MAIN_CLASS = "com.simple.Main";
private static final Set<String> modules = Set.of(TEST_MODULE);
public static void buildTestModule() throws Exception {
// javac -d mods/$TESTMODULE --module-path MOD_DIR modulepath/src/$TESTMODULE/**
JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE),
MODS_DIR.resolve(TEST_MODULE),
MODS_DIR.toString());
}
public static void main(String... args) throws Exception {
// compile the modules and create the modular jar files
buildTestModule();
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Xlog:cds",
"-Xlog:module=debug",
"NewModuleFinderTest$Helper");
OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "exec");
out.shouldHaveExitValue(0);
out.shouldContain("define_module(): creation of module: com.simple,");
}
static class Helper {
public static void main(String... args) {
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
Configuration parent = ModuleLayer.boot().configuration();
Configuration cf = parent.resolveAndBind(ModuleFinder.of(),
finder,
modules);
ClassLoader scl = ClassLoader.getSystemClassLoader();
ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl);
Module m1 = layer.findModule(TEST_MODULE).get();
System.out.println("Module = " + m1);
if (m1 != null) {
System.out.println("Success");
} else {
throw new RuntimeException("Module should not be null");
}
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2020, 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.
*
*/
/*
* @test
* @bug 8249276
* @summary Make sure that archived module graph is not loaded if critical classes have been redefined.
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @requires vm.cds
* @requires vm.flavor != "minimal"
* @modules java.instrument
* @run driver RedefineClassesInModuleGraph
*/
import jdk.test.lib.process.OutputAnalyzer;
public class RedefineClassesInModuleGraph {
public static String appClasses[] = {
RedefineClassesInModuleGraphApp.class.getName(),
};
public static String agentClasses[] = {
RedefineClassesInModuleGraphAgent.class.getName(),
RedefineClassesInModuleGraphTransformer.class.getName(),
};
private static final String MANIFEST =
"Manifest-Version: 1.0\n" +
"Premain-Class: RedefineClassesInModuleGraphAgent\n" +
"Can-Retransform-Classes: true\n" +
"Can-Redefine-Classes: true\n";
public static void main(String[] args) throws Throwable {
String agentJar =
ClassFileInstaller.writeJar("RedefineClassesInModuleGraphAgent.jar",
ClassFileInstaller.Manifest.fromString(MANIFEST),
agentClasses);
String appJar =
ClassFileInstaller.writeJar("RedefineClassesInModuleGraphApp.jar", appClasses);
TestCommon.testDump(appJar, agentClasses);
TestCommon.run(
"-cp", appJar,
"-javaagent:" + agentJar,
RedefineClassesInModuleGraphApp.class.getName())
.assertNormalExit();
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2020, 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.
*
*/
import java.lang.instrument.Instrumentation;
public class RedefineClassesInModuleGraphAgent {
private static Instrumentation savedInstrumentation;
public static void premain(String agentArguments, Instrumentation instrumentation) {
instrumentation.addTransformer(new RedefineClassesInModuleGraphTransformer(), /*canRetransform=*/true);
savedInstrumentation = instrumentation;
}
public static Instrumentation getInstrumentation() {
return savedInstrumentation;
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2020, 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.
*
*/
public class RedefineClassesInModuleGraphApp {
public static void main(String args[]) {
Module m = Object.class.getModule();
ModuleLayer ml = m.getLayer();
System.out.println(m);
System.out.println(ml);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2020, 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.
*
*/
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class RedefineClassesInModuleGraphTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
System.out.println("transforming " + name);
if (name.equals("java/lang/Module") ||
name.equals("java/lang/ModuleLayer") ||
name.equals("java/lang/module/ResolvedModule")) {
throw new RuntimeException("Classes used by the module graph should never be transformed by Java agent");
}
return null;
}
}

View File

@ -24,7 +24,7 @@
/**
* @test
* @requires vm.cds & !vm.jvmci
* @requires vm.cds & !vm.graal.enabled
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* @run driver OptimizeModuleHandlingTest
* @summary test module path changes for optimization of
@ -63,8 +63,8 @@ public class OptimizeModuleHandlingTest {
private static String CLASS_FOUND_MESSAGE = "com.foos.Test found";
private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test";
private static String OPTIMIZE_ENABLED = "Using optimized module handling enabled";
private static String OPTIMIZE_DISABLED = "Using optimized module handling disabled";
private static String OPTIMIZE_ENABLED = "optimized module handling: enabled";
private static String OPTIMIZE_DISABLED = "optimized module handling: disabled";
private static String MAIN_FROM_JAR = "class,load.*com.bars.Main.*[.]jar";
private static String MAIN_FROM_CDS = "class,load.*com.bars.Main.*shared objects file";
private static String TEST_FROM_JAR = "class,load.*com.foos.Test.*[.]jar";

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -53,7 +53,8 @@ public class ReplaceCriticalClasses {
.setXShareMode("dump")
.setArchiveName(ReplaceCriticalClasses.class.getName() + ".jsa")
.setUseVersion(false)
.addSuffix("-showversion");
.addSuffix("-showversion")
.addSuffix("-Xlog:cds");
CDSTestUtils.run(opts).assertNormalExit("");
launchChildProcesses(getTests());
@ -80,6 +81,8 @@ public class ReplaceCriticalClasses {
"-early -notshared java/lang/String",
"-early -notshared java/lang/Cloneable",
"-early -notshared java/io/Serializable",
"-early -notshared java/lang/Module",
"-early -notshared java/lang/ModuleLayer",
// CDS should not be disabled -- these critical classes cannot be replaced because
// JvmtiExport::early_class_hook_env() is false.
@ -87,13 +90,8 @@ public class ReplaceCriticalClasses {
"java/lang/String",
"java/lang/Cloneable",
"java/io/Serializable",
/* Try to replace classes that are used by the archived subgraph graphs.
The following test cases are in ReplaceCriticalClassesForSubgraphs.java.
"-early -notshared -subgraph java/lang/module/ResolvedModule jdk.internal.module.ArchivedModuleGraph",
"-early -notshared -subgraph java/lang/Long java.lang.Long$LongCache",
"-subgraph java/lang/Long java.lang.Long$LongCache",
*/
"java/lang/Module",
"java/lang/ModuleLayer",
// Replace classes that are loaded after JVMTI_PHASE_PRIMORDIAL. It's OK to replace
// such
@ -116,12 +114,13 @@ public class ReplaceCriticalClasses {
static void launchChild(String args[]) throws Throwable {
if (args.length < 1) {
throw new RuntimeException("Invalid test case. Should be <-early> <-subgraph> <-notshared> klassName subgraphKlass");
throw new RuntimeException("Invalid test case. Should be <-early> <-subgraph> <-notshared> <-nowhitebox> klassName subgraphKlass");
}
String klassName = null;
String subgraphKlass = null;
String early = "";
boolean subgraph = false;
boolean whitebox = true;
String shared = "-shared";
for (int i=0; i<args.length-1; i++) {
@ -130,6 +129,8 @@ public class ReplaceCriticalClasses {
early = "-early,";
} else if (opt.equals("-subgraph")) {
subgraph = true;
} else if (opt.equals("-nowhitebox")) {
whitebox = false;
} else if (opt.equals("-notshared")) {
shared = opt;
} else {
@ -166,10 +167,11 @@ public class ReplaceCriticalClasses {
.addSuffix("-showversion",
"-Xlog:cds",
"-XX:+UnlockDiagnosticVMOptions",
agent,
"-XX:+WhiteBoxAPI",
"-Xbootclasspath/a:" + ClassFileInstaller.getJarPath("whitebox.jar"));
agent);
if (whitebox) {
opts.addSuffix("-XX:+WhiteBoxAPI",
"-Xbootclasspath/a:" + ClassFileInstaller.getJarPath("whitebox.jar"));
}
if (subgraph) {
opts.addSuffix("-Xlog:cds,cds+heap");
}
@ -191,6 +193,8 @@ public class ReplaceCriticalClasses {
if (expectShared) {
if (!out.getOutput().contains("UseSharedSpaces: Unable to map at required address in java heap")) {
out.shouldContain(subgraphInit);
// If the subgraph is successfully initialized, the specified shared class must not be rewritten.
out.shouldNotContain("Rewriting done.");
}
} else {
out.shouldNotContain(subgraphInit);
@ -200,15 +204,19 @@ public class ReplaceCriticalClasses {
}
static void testInChild(boolean shouldBeShared, Class klass) {
WhiteBox wb = WhiteBox.getWhiteBox();
try {
WhiteBox wb = WhiteBox.getWhiteBox();
if (shouldBeShared && !wb.isSharedClass(klass)) {
throw new RuntimeException(klass + " should be shared but but actually is not.");
if (shouldBeShared && !wb.isSharedClass(klass)) {
throw new RuntimeException(klass + " should be shared but but actually is not.");
}
if (!shouldBeShared && wb.isSharedClass(klass)) {
throw new RuntimeException(klass + " should not be shared but actually is.");
}
System.out.println("wb.isSharedClass(" + klass + "): " + wb.isSharedClass(klass) + " == " + shouldBeShared);
} catch (UnsatisfiedLinkError e) {
System.out.println("WhiteBox is disabled -- because test has -nowhitebox");
}
if (!shouldBeShared && wb.isSharedClass(klass)) {
throw new RuntimeException(klass + " should not be shared but actually is.");
}
System.out.println("wb.isSharedClass(klass): " + wb.isSharedClass(klass) + " == " + shouldBeShared);
String strings[] = {
// interned strings from j.l.Object

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -40,10 +40,21 @@ public class ReplaceCriticalClassesForSubgraphs extends ReplaceCriticalClasses {
public String[] getTests() {
String tests[] = {
// Try to replace classes that are used by the archived subgraph graphs.
// Try to replace classes that are used by the archived subgraph graphs. (CDS should be disabled)
"-early -notshared -subgraph java/lang/module/ResolvedModule jdk.internal.module.ArchivedModuleGraph",
"-early -notshared -subgraph java/lang/Long java.lang.Long$LongCache",
// CDS should not be disabled -- these critical classes cannot be replaced because
// JvmtiExport::early_class_hook_env() is false.
"-subgraph java/lang/module/ResolvedModule jdk.internal.module.ArchivedModuleGraph",
"-subgraph java/lang/Long java.lang.Long$LongCache",
// Tests for archived full module graph. We cannot use whitebox, which requires appending to bootclasspath.
// VM will disable full module graph if bootclasspath is appended.
"-nowhitebox -early -notshared -subgraph java/lang/Module jdk.internal.module.ArchivedBootLayer",
"-nowhitebox -early -notshared -subgraph java/lang/ModuleLayer jdk.internal.module.ArchivedBootLayer",
"-nowhitebox -subgraph java/lang/Module jdk.internal.module.ArchivedBootLayer",
"-nowhitebox -subgraph java/lang/ModuleLayer jdk.internal.module.ArchivedBootLayer",
};
return tests;
}

View File

@ -34,13 +34,18 @@ import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class ModulesTest {
// If modules in the system image have been archived in CDS, no Modules will
// be dynamically created at runtime. Disable CDS so all of the expected messages
// are printed.
private static String XSHARE_OFF = "-Xshare:off";
public static void main(String[] args) throws Exception {
testModuleTrace("-Xlog:module=trace", "-version");
testModuleLoad("-Xlog:module+load", "-version");
testModuleUnload("-Xlog:module+unload", "-version");
testModuleTrace("-Xlog:module=trace", XSHARE_OFF, "-version");
testModuleLoad("-Xlog:module+load", XSHARE_OFF, "-version");
testModuleUnload("-Xlog:module+unload", XSHARE_OFF, "-version");
// same as -Xlog:module+load -Xlog:module+unload
testModuleLoad("-verbose:module", "-version");
testModuleLoad("-verbose:module", XSHARE_OFF, "-version");
}
static void testModuleTrace(String... args) throws Exception {