This commit is contained in:
Alejandro Murillo 2016-07-08 12:12:54 -07:00
commit 7cd48c89d3
32 changed files with 1389 additions and 77 deletions

@ -45,7 +45,8 @@ ifeq ($(call check-jvm-feature, dtrace), true)
$(DTRACE_GENSRC_DIR)/%.h: $(DTRACE_SOURCE_DIR)/%.d
$(call LogInfo, Generating dtrace header file $(@F))
$(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR))
$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, $(CC) -E $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)
$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
( $(CC) -E $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d ) )
$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
# Process all .d files in DTRACE_SOURCE_DIR. They are:

@ -68,7 +68,7 @@ ifeq ($(call check-jvm-feature, dtrace), true)
$1: $$(BUILD_DTRACE_GEN_OFFSETS)
$$(call LogInfo, Generating dtrace $2 file $$(@F))
$$(call MakeDir, $$(@D))
$$(call ExecuteWithLog, $$@, $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@)
$$(call ExecuteWithLog, $$@, ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@ ) )
TARGETS += $1
endef

@ -501,13 +501,26 @@ ClassLoaderData::~ClassLoaderData() {
}
}
/**
* Returns true if this class loader data is for the platform class loader.
*/
// Returns true if this class loader data is for the system class loader.
bool ClassLoaderData::is_system_class_loader_data() const {
return SystemDictionary::is_system_class_loader(class_loader());
}
// Returns true if this class loader data is for the platform class loader.
bool ClassLoaderData::is_platform_class_loader_data() const {
return SystemDictionary::is_platform_class_loader(class_loader());
}
// Returns true if this class loader data is one of the 3 builtin
// (boot, application/system or platform) class loaders. Note, the
// builtin loaders are not freed by a GC.
bool ClassLoaderData::is_builtin_class_loader_data() const {
Handle classLoaderHandle = class_loader();
return (is_the_null_class_loader_data() ||
SystemDictionary::is_system_class_loader(classLoaderHandle) ||
SystemDictionary::is_platform_class_loader(classLoaderHandle));
}
Metaspace* ClassLoaderData::metaspace_non_null() {
assert(!DumpSharedSpaces, "wrong metaspace!");
// If the metaspace has not been allocated, create a new one. Might want
@ -957,12 +970,6 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
data = _head;
while (data != NULL) {
if (data->is_alive(is_alive_closure)) {
if (data->packages_defined()) {
data->packages()->purge_all_package_exports();
}
if (data->modules_defined()) {
data->modules()->purge_all_module_reads();
}
// clean metaspace
if (walk_all_metadata) {
data->classes_do(InstanceKlass::purge_previous_versions);
@ -990,6 +997,23 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
}
if (seen_dead_loader) {
// Walk a ModuleEntry's reads and a PackageEntry's exports lists
// to determine if there are modules on those lists that are now
// dead and should be removed. A module's life cycle is equivalent
// to its defining class loader's life cycle. Since a module is
// considered dead if its class loader is dead, these walks must
// occur after each class loader's aliveness is determined.
data = _head;
while (data != NULL) {
if (data->packages_defined()) {
data->packages()->purge_all_package_exports();
}
if (data->modules_defined()) {
data->modules()->purge_all_module_reads();
}
data = data->next();
}
post_class_unload_events();
}

@ -270,7 +270,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
bool is_the_null_class_loader_data() const {
return this == _the_null_class_loader_data;
}
bool is_system_class_loader_data() const;
bool is_platform_class_loader_data() const;
bool is_builtin_class_loader_data() const;
// The Metaspace is created lazily so may be NULL. This
// method will allocate a Metaspace if needed.

@ -248,7 +248,7 @@ inline void SimpleCompactHashtable::iterate(const I& iterator) {
} else {
u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]);
while (entry < entry_max) {
iterator.do_value(_base_address, entry[0]);
iterator.do_value(_base_address, entry[1]);
entry += 2;
}
}

@ -40,7 +40,6 @@
ModuleEntry* ModuleEntryTable::_javabase_module = NULL;
void ModuleEntry::set_location(Symbol* location) {
if (_location != NULL) {
// _location symbol's refcounts are managed by ModuleEntry,
@ -115,10 +114,35 @@ void ModuleEntry::add_read(ModuleEntry* m) {
// Lazily create a module's reads list
_reads = new (ResourceObj::C_HEAP, mtModule)GrowableArray<ModuleEntry*>(MODULE_READS_SIZE, true);
}
// Determine, based on this newly established read edge to module m,
// if this module's read list should be walked at a GC safepoint.
set_read_walk_required(m->loader_data());
// Establish readability to module m
_reads->append_if_missing(m);
}
}
// If the module's loader, that a read edge is being established to, is
// not the same loader as this module's and is not one of the 3 builtin
// class loaders, then this module's reads list must be walked at GC
// safepoint. Modules have the same life cycle as their defining class
// loaders and should be removed if dead.
void ModuleEntry::set_read_walk_required(ClassLoaderData* m_loader_data) {
assert_locked_or_safepoint(Module_lock);
if (!_must_walk_reads &&
loader_data() != m_loader_data &&
!m_loader_data->is_builtin_class_loader_data()) {
_must_walk_reads = true;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
log_trace(modules)("ModuleEntry::set_read_walk_required(): module %s reads list must be walked",
(name() != NULL) ? name()->as_C_string() : UNNAMED_MODULE);
}
}
}
bool ModuleEntry::has_reads() const {
assert_locked_or_safepoint(Module_lock);
return ((_reads != NULL) && !_reads->is_empty());
@ -127,14 +151,28 @@ bool ModuleEntry::has_reads() const {
// Purge dead module entries out of reads list.
void ModuleEntry::purge_reads() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
if (has_reads()) {
if (_must_walk_reads && has_reads()) {
// This module's _must_walk_reads flag will be reset based
// on the remaining live modules on the reads list.
_must_walk_reads = false;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
log_trace(modules)("ModuleEntry::purge_reads(): module %s reads list being walked",
(name() != NULL) ? name()->as_C_string() : UNNAMED_MODULE);
}
// Go backwards because this removes entries that are dead.
int len = _reads->length();
for (int idx = len - 1; idx >= 0; idx--) {
ModuleEntry* module_idx = _reads->at(idx);
ClassLoaderData* cld = module_idx->loader();
if (cld->is_unloading()) {
ClassLoaderData* cld_idx = module_idx->loader_data();
if (cld_idx->is_unloading()) {
_reads->delete_at(idx);
} else {
// Update the need to walk this module's reads based on live modules
set_read_walk_required(cld_idx);
}
}
}
@ -248,7 +286,7 @@ ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle
entry->set_module(loader_data->add_handle(module_handle));
}
entry->set_loader(loader_data);
entry->set_loader_data(loader_data);
entry->set_version(version);
entry->set_location(location);
@ -375,11 +413,11 @@ void ModuleEntryTable::print(outputStream* st) {
void ModuleEntry::print(outputStream* st) {
ResourceMark rm;
st->print_cr("entry "PTR_FORMAT" name %s module "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT,
st->print_cr("entry " PTR_FORMAT " name %s module " PTR_FORMAT " loader %s version %s location %s strict %s next " PTR_FORMAT,
p2i(this),
name() == NULL ? UNNAMED_MODULE : name()->as_C_string(),
p2i(module()),
loader()->loader_name(),
loader_data()->loader_name(),
version() != NULL ? version()->as_C_string() : "NULL",
location() != NULL ? location()->as_C_string() : "NULL",
BOOL_TO_STR(!can_read_all_unnamed()), p2i(next()));
@ -401,5 +439,5 @@ void ModuleEntryTable::verify() {
}
void ModuleEntry::verify() {
guarantee(loader() != NULL, "A module entry must be associated with a loader.");
guarantee(loader_data() != NULL, "A module entry must be associated with a loader.");
}

@ -43,6 +43,7 @@ class ModuleClosure;
// It contains:
// - Symbol* containing the module's name.
// - pointer to the java.lang.reflect.Module for this module.
// - pointer to the java.security.ProtectionDomain shared by classes defined to this module.
// - ClassLoaderData*, class loader of this module.
// - a growable array containg other module entries that this module can read.
// - a flag indicating if this module can read all unnamed modules.
@ -54,56 +55,58 @@ private:
jobject _module; // java.lang.reflect.Module
jobject _pd; // java.security.ProtectionDomain, cached
// for shared classes from this module
ClassLoaderData* _loader;
ClassLoaderData* _loader_data;
GrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module
Symbol* _version; // module version number
Symbol* _location; // module location
bool _can_read_all_unnamed;
bool _has_default_read_edges; // JVMTI redefine/retransform support
bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules
TRACE_DEFINE_TRACE_ID_FIELD;
enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read.
public:
void init() {
_module = NULL;
_loader = NULL;
_loader_data = NULL;
_pd = NULL;
_reads = NULL;
_version = NULL;
_location = NULL;
_can_read_all_unnamed = false;
_has_default_read_edges = false;
_must_walk_reads = false;
}
Symbol* name() const { return literal(); }
void set_name(Symbol* n) { set_literal(n); }
Symbol* name() const { return literal(); }
void set_name(Symbol* n) { set_literal(n); }
jobject module() const { return _module; }
void set_module(jobject j) { _module = j; }
jobject module() const { return _module; }
void set_module(jobject j) { _module = j; }
// The shared ProtectionDomain reference is set once the VM loads a shared class
// originated from the current Module. The referenced ProtectionDomain object is
// created by the ClassLoader when loading a class (shared or non-shared) from the
// Module for the first time. This ProtectionDomain object is used for all
// classes from the Module loaded by the same ClassLoader.
Handle shared_protection_domain();
void set_shared_protection_domain(ClassLoaderData *loader_data,
Handle pd);
Handle shared_protection_domain();
void set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd);
ClassLoaderData* loader() const { return _loader; }
void set_loader(ClassLoaderData* l) { _loader = l; }
ClassLoaderData* loader_data() const { return _loader_data; }
void set_loader_data(ClassLoaderData* l) { _loader_data = l; }
Symbol* version() const { return _version; }
void set_version(Symbol* version);
Symbol* version() const { return _version; }
void set_version(Symbol* version);
Symbol* location() const { return _location; }
void set_location(Symbol* location);
Symbol* location() const { return _location; }
void set_location(Symbol* location);
bool can_read(ModuleEntry* m) const;
bool has_reads() const;
void add_read(ModuleEntry* m);
bool can_read(ModuleEntry* m) const;
bool has_reads() const;
void add_read(ModuleEntry* m);
void set_read_walk_required(ClassLoaderData* m_loader_data);
bool is_named() const { return (literal() != NULL); }
bool is_named() const { return (name() != NULL); }
bool can_read_all_unnamed() const {
assert(is_named() || _can_read_all_unnamed == true,
@ -178,7 +181,7 @@ private:
ModuleEntry* _unnamed_module;
ModuleEntry* new_entry(unsigned int hash, Handle module_handle, Symbol* name, Symbol* version,
Symbol* location, ClassLoaderData* class_loader);
Symbol* location, ClassLoaderData* loader_data);
void add_entry(int index, ModuleEntry* new_entry);
int entry_size() const { return BasicHashtable<mtModule>::entry_size(); }

@ -113,7 +113,7 @@ static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring packag
const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
if (package_name == NULL) return NULL;
TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL);
PackageEntryTable* package_entry_table = module_entry->loader()->packages();
PackageEntryTable* package_entry_table = module_entry->loader_data()->packages();
assert(package_entry_table != NULL, "Unexpected null package entry table");
return package_entry_table->lookup_only(pkg_symbol);
}
@ -868,7 +868,7 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
package_name, module_entry->name()->as_C_string());
TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
PackageEntryTable* package_table = module_entry->loader()->packages();
PackageEntryTable* package_table = module_entry->loader_data()->packages();
assert(package_table != NULL, "Missing package_table");
bool pkg_exists = false;

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
@ -53,12 +54,40 @@ void PackageEntry::add_qexport(ModuleEntry* m) {
if (!has_qual_exports_list()) {
// Lazily create a package's qualified exports list.
// Initial size is small, do not anticipate export lists to be large.
_qualified_exports =
new (ResourceObj::C_HEAP, mtModule) GrowableArray<ModuleEntry*>(QUAL_EXP_SIZE, true);
_qualified_exports = new (ResourceObj::C_HEAP, mtModule) GrowableArray<ModuleEntry*>(QUAL_EXP_SIZE, true);
}
// Determine, based on this newly established export to module m,
// if this package's export list should be walked at a GC safepoint.
set_export_walk_required(m->loader_data());
// Establish exportability to module m
_qualified_exports->append_if_missing(m);
}
// If the module's loader, that an export is being established to, is
// not the same loader as this module's and is not one of the 3 builtin
// class loaders, then this package's export list must be walked at GC
// safepoint. Modules have the same life cycle as their defining class
// loaders and should be removed if dead.
void PackageEntry::set_export_walk_required(ClassLoaderData* m_loader_data) {
assert_locked_or_safepoint(Module_lock);
ModuleEntry* this_pkg_mod = module();
if (!_must_walk_exports &&
(this_pkg_mod == NULL || this_pkg_mod->loader_data() != m_loader_data) &&
!m_loader_data->is_builtin_class_loader_data()) {
_must_walk_exports = true;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
assert(name() != NULL, "PackageEntry without a valid name");
log_trace(modules)("PackageEntry::set_export_walk_required(): package %s defined in module %s, exports list must be walked",
name()->as_C_string(),
(this_pkg_mod == NULL || this_pkg_mod->name() == NULL) ?
UNNAMED_MODULE : this_pkg_mod->name()->as_C_string());
}
}
}
// Set the package's exported states based on the value of the ModuleEntry.
void PackageEntry::set_exported(ModuleEntry* m) {
MutexLocker m1(Module_lock);
@ -96,14 +125,34 @@ void PackageEntry::set_is_exported_allUnnamed() {
// Remove dead module entries within the package's exported list.
void PackageEntry::purge_qualified_exports() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
if (_qualified_exports != NULL) {
if (_must_walk_exports &&
_qualified_exports != NULL &&
!_qualified_exports->is_empty()) {
ModuleEntry* pkg_module = module();
// This package's _must_walk_exports flag will be reset based
// on the remaining live modules on the exports list.
_must_walk_exports = false;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
assert(name() != NULL, "PackageEntry without a valid name");
ModuleEntry* pkg_mod = module();
log_trace(modules)("PackageEntry::purge_qualified_exports(): package %s defined in module %s, exports list being walked",
name()->as_C_string(),
(pkg_mod == NULL || pkg_mod->name() == NULL) ? UNNAMED_MODULE : pkg_mod->name()->as_C_string());
}
// Go backwards because this removes entries that are dead.
int len = _qualified_exports->length();
for (int idx = len - 1; idx >= 0; idx--) {
ModuleEntry* module_idx = _qualified_exports->at(idx);
ClassLoaderData* cld = module_idx->loader();
if (cld->is_unloading()) {
ClassLoaderData* cld_idx = module_idx->loader_data();
if (cld_idx->is_unloading()) {
_qualified_exports->delete_at(idx);
} else {
// Update the need to walk this package's exports based on live modules
set_export_walk_required(cld_idx);
}
}
}
@ -297,8 +346,8 @@ void PackageEntryTable::print(outputStream* st) {
void PackageEntry::print(outputStream* st) {
ResourceMark rm;
st->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index "
INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next "PTR_FORMAT,
st->print_cr("package entry " PTR_FORMAT " name %s module %s classpath_index "
INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next " PTR_FORMAT,
p2i(this), name()->as_C_string(),
(module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE),
_classpath_index, _is_exported_unqualified, _is_exported_allUnnamed, p2i(next()));

@ -69,6 +69,7 @@ private:
s2 _classpath_index;
bool _is_exported_unqualified;
bool _is_exported_allUnnamed;
bool _must_walk_exports;
GrowableArray<ModuleEntry*>* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint
GrowableArray<ModuleEntry*>* _qualified_exports;
TRACE_DEFINE_TRACE_ID_FIELD;
@ -82,6 +83,7 @@ public:
_classpath_index = -1;
_is_exported_unqualified = false;
_is_exported_allUnnamed = false;
_must_walk_exports = false;
_exported_pending_delete = NULL;
_qualified_exports = NULL;
}
@ -147,6 +149,7 @@ public:
// add the module to the package's qualified exports
void add_qexport(ModuleEntry* m);
void set_export_walk_required(ClassLoaderData* m_loader_data);
PackageEntry* next() const {
return (PackageEntry*)HashtableEntry<Symbol*, mtModule>::next();

@ -175,9 +175,18 @@ bool SystemDictionary::is_parallelDefine(Handle class_loader) {
return false;
}
/**
* Returns true if the passed class loader is the platform class loader.
*/
// Returns true if the passed class loader is the builtin application class loader
// or a custom system class loader. A customer system class loader can be
// specified via -Djava.system.class.loader.
bool SystemDictionary::is_system_class_loader(Handle class_loader) {
if (class_loader.is_null()) {
return false;
}
return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() ||
class_loader() == _java_system_loader);
}
// Returns true if the passed class loader is the platform class loader.
bool SystemDictionary::is_platform_class_loader(Handle class_loader) {
if (class_loader.is_null()) {
return false;

@ -660,6 +660,7 @@ public:
static instanceKlassHandle load_shared_class(Symbol* class_name,
Handle class_loader,
TRAPS);
static bool is_system_class_loader(Handle class_loader);
static bool is_platform_class_loader(Handle class_loader);
protected:

@ -48,10 +48,10 @@ void PreservedMarks::restore_and_increment(volatile size_t* const total_size_add
#ifndef PRODUCT
void PreservedMarks::assert_empty() {
assert(_stack.is_empty(), "stack expected to be empty, size = "SIZE_FORMAT,
assert(_stack.is_empty(), "stack expected to be empty, size = " SIZE_FORMAT,
_stack.size());
assert(_stack.cache_size() == 0,
"stack expected to have no cached segments, cache size = "SIZE_FORMAT,
"stack expected to have no cached segments, cache size = " SIZE_FORMAT,
_stack.cache_size());
}
#endif // ndef PRODUCT

@ -419,21 +419,20 @@ void Rewriter::scan_method(Method* method, bool reverse, bool* invokespecial_err
InstanceKlass* klass = method->method_holder();
u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1);
constantPoolHandle cp(method->constants());
Symbol* field_name = cp->name_ref_at(bc_index);
Symbol* field_sig = cp->signature_ref_at(bc_index);
Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index));
if (klass->name() == ref_class_name) {
Symbol* field_name = cp->name_ref_at(bc_index);
Symbol* field_sig = cp->signature_ref_at(bc_index);
fieldDescriptor fd;
klass->find_field(field_name, field_sig, &fd);
if (fd.access_flags().is_final()) {
if (fd.access_flags().is_static()) {
assert(c == Bytecodes::_putstatic, "must be putstatic");
if (!method->is_static_initializer()) {
fd.set_has_initialized_final_update(true);
}
} else {
assert(c == Bytecodes::_putfield, "must be putfield");
if (!method->is_object_initializer()) {
fd.set_has_initialized_final_update(true);
}

@ -584,27 +584,26 @@ static bool verify_special_jvm_flags() {
// Parses a size specification string.
bool Arguments::atojulong(const char *s, julong* result) {
julong n = 0;
int args_read = 0;
bool is_hex = false;
// Skip leading 0[xX] for hexadecimal
if (*s =='0' && (*(s+1) == 'x' || *(s+1) == 'X')) {
s += 2;
is_hex = true;
args_read = sscanf(s, JULONG_FORMAT_X, &n);
} else {
args_read = sscanf(s, JULONG_FORMAT, &n);
}
if (args_read != 1) {
// First char must be a digit. Don't allow negative numbers or leading spaces.
if (!isdigit(*s)) {
return false;
}
while (*s != '\0' && (isdigit(*s) || (is_hex && isxdigit(*s)))) {
s++;
}
// 4705540: illegal if more characters are found after the first non-digit
if (strlen(s) > 1) {
bool is_hex = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
char* remainder;
errno = 0;
n = strtoull(s, &remainder, (is_hex ? 16 : 10));
if (errno != 0) {
return false;
}
switch (*s) {
// Fail if no number was read at all or if the remainder contains more than a single non-digit character.
if (remainder == s || strlen(remainder) > 1) {
return false;
}
switch (*remainder) {
case 'T': case 't':
*result = n * G * K;
// Check for overflow.

@ -205,16 +205,39 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt,
static void print_oom_reasons(outputStream* st) {
st->print_cr("# Possible reasons:");
st->print_cr("# The system is out of physical RAM or swap space");
st->print_cr("# In 32 bit mode, the process size limit was hit");
if (UseCompressedOops) {
st->print_cr("# The process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap");
}
if (LogBytesPerWord == 2) {
st->print_cr("# In 32 bit mode, the process size limit was hit");
}
st->print_cr("# Possible solutions:");
st->print_cr("# Reduce memory load on the system");
st->print_cr("# Increase physical memory or swap space");
st->print_cr("# Check if swap backing store is full");
st->print_cr("# Use 64 bit Java on a 64 bit OS");
if (LogBytesPerWord == 2) {
st->print_cr("# Use 64 bit Java on a 64 bit OS");
}
st->print_cr("# Decrease Java heap size (-Xmx/-Xms)");
st->print_cr("# Decrease number of Java threads");
st->print_cr("# Decrease Java thread stack sizes (-Xss)");
st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize=");
if (UseCompressedOops) {
switch (Universe::narrow_oop_mode()) {
case Universe::UnscaledNarrowOop:
st->print_cr("# JVM is running with Unscaled Compressed Oops mode in which the Java heap is");
st->print_cr("# placed in the first 4GB address space. The Java Heap base address is the");
st->print_cr("# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress");
st->print_cr("# to set the Java Heap base and to place the Java Heap above 4GB virtual address.");
break;
case Universe::ZeroBasedNarrowOop:
st->print_cr("# JVM is running with Zero Based Compressed Oops mode in which the Java heap is");
st->print_cr("# placed in the first 32GB address space. The Java Heap base address is the");
st->print_cr("# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress");
st->print_cr("# to set the Java Heap base and to place the Java Heap above 32GB virtual address.");
break;
}
}
st->print_cr("# This output file may be truncated or incomplete.");
}

@ -395,6 +395,17 @@ hotspot_jprt = \
:hotspot_fast_gc_gcold \
:hotspot_fast_runtime \
:hotspot_fast_serviceability
hotspot_runtime_tier2 = \
runtime/ \
serviceability/ \
-:hotspot_fast_runtime \
-:hotspot_fast_serviceability \
-:hotspot_runtime_tier2_platform_agnostic
hotspot_runtime_tier2_platform_agnostic = \
runtime/SelectionResolution \
-:hotspot_fast_runtime
#All tests that depends on nashorn extension.
#

@ -0,0 +1,234 @@
/*
* Copyright (c) 2016, 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 gc.g1.humongousObjects;
import jdk.test.lib.Utils;
import sun.hotspot.WhiteBox;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
/**
* @test TestNoAllocationsInHRegions
* @summary Checks that no additional allocations are made in humongous regions
* @requires vm.gc.G1
* @library /testlibrary /test/lib /
* @modules java.management java.base/jdk.internal.misc
* @build sun.hotspot.WhiteBox
* gc.testlibrary.Helpers
* gc.g1.humongousObjects.TestNoAllocationsInHRegions
*
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
*
* @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0
* -Xlog:gc=trace:file=TestNoAllocationsInHRegions10.log
* gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 10
*
* @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0
* -Xlog:gc=trace:file=TestNoAllocationsInHRegions50.log
* gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 50
*
* @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0
* -Xlog:gc=trace:file=TestNoAllocationsInHRegions70.log
* gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 70
*/
public class TestNoAllocationsInHRegions {
private static final WhiteBox WB = WhiteBox.getWhiteBox();
private static final Random RND = Utils.getRandomInstance();
private static final int G1_REGION_SIZE = WB.g1RegionSize();
private static final int[] HUMONGOUS_SIZES = {G1_REGION_SIZE / 2, G1_REGION_SIZE + 1, G1_REGION_SIZE * 2 + 1};
private static final int ALLOC_THREAD_COUNT = 5;
// We fill specified part of heap with humongous objects - we need public static to prevent escape analysis to
// collect this field
public static LinkedList<byte[]> humongousAllocations = new LinkedList<>();
private static volatile boolean shouldStop = false;
private static volatile Error error = null;
static class Allocator implements Runnable {
private final List<byte[]> liveObjects = new LinkedList<>();
private int usedMemory = 0;
public final Runnable[] actions;
/**
* Maximum size of simple allocation
*/
private static final int MAX_ALLOCATION_SIZE = (int) (G1_REGION_SIZE / 2 * 0.9);
/**
* Maximum size of dead (i.e. one which is made unreachable right after allocation) object
*/
private static final int DEAD_OBJECT_MAX_SIZE = G1_REGION_SIZE / 10;
public Allocator(int maxAllocationMemory) {
actions = new Runnable[]{
// Allocation
() -> {
if (maxAllocationMemory - usedMemory != 0) {
int arraySize = RND.nextInt(Math.min(maxAllocationMemory - usedMemory,
MAX_ALLOCATION_SIZE));
if (arraySize != 0) {
byte[] allocation = new byte[arraySize];
liveObjects.add(allocation);
usedMemory += arraySize;
// Sanity check
if (WB.g1IsHumongous(allocation)) {
String errorMessage = String.format("Test Bug: Byte array of size"
+ " %d is expected to be non-humongous but it is humongous",
allocation.length);
System.out.println(errorMessage);
error = new Error(errorMessage);
shouldStop = true;
}
// Test check
if (WB.g1BelongsToHumongousRegion(WB.getObjectAddress(allocation))) {
String errorMessage = String.format("Non-humongous allocation of byte array of "
+ "length %d and size %d with address %d was made in Humongous Region",
allocation.length, WB.getObjectSize(allocation),
WB.getObjectAddress(allocation));
System.out.println(errorMessage);
error = new Error(errorMessage);
shouldStop = true;
}
}
}
},
// Deallocation
() -> {
if (liveObjects.size() != 0) {
int elementNum = RND.nextInt(liveObjects.size());
int shouldFree = liveObjects.get(elementNum).length;
liveObjects.remove(elementNum);
usedMemory -= shouldFree;
}
},
// Dead object allocation
() -> {
int size = RND.nextInt(DEAD_OBJECT_MAX_SIZE);
byte[] deadObject = new byte[size];
},
// Check
() -> {
List<byte[]> wrongHumongousAllocations = liveObjects.stream()
.filter(WB::g1IsHumongous)
.collect(Collectors.toList());
if (wrongHumongousAllocations.size() > 0) {
wrongHumongousAllocations.stream().forEach(a ->
System.out.format("Non-humongous allocation of byte array of length %d and"
+ " size %d with address %d was made in Humongous Region",
a.length, WB.getObjectSize(a), WB.getObjectAddress(a)));
error = new Error("Some non-humongous allocations were made to humongous region");
shouldStop = true;
}
}
};
}
@Override
public void run() {
while (!shouldStop) {
actions[RND.nextInt(actions.length)].run();
Thread.yield();
}
}
}
public static void main(String[] args) {
if (args.length != 2) {
throw new Error("Test Bug: Expected duration (in seconds) and percent of allocated regions were not "
+ "provided as command line argument");
}
// test duration
long duration = Integer.parseInt(args[0]) * 1000L;
// part of heap preallocated with humongous objects (in percents)
int percentOfAllocatedHeap = Integer.parseInt(args[1]);
long startTime = System.currentTimeMillis();
long initialFreeRegionsCount = WB.g1NumFreeRegions();
int regionsToAllocate = (int) ((double) initialFreeRegionsCount / 100.0 * percentOfAllocatedHeap);
long freeRegionLeft = initialFreeRegionsCount - regionsToAllocate;
System.out.println("Regions to allocate: " + regionsToAllocate + "; regions to left free: " + freeRegionLeft);
int maxMemoryPerAllocThread = (int) ((Runtime.getRuntime().freeMemory() / 100.0
* (100 - percentOfAllocatedHeap)) / ALLOC_THREAD_COUNT * 0.5);
System.out.println("Using " + maxMemoryPerAllocThread / 1024 + "KB for each of " + ALLOC_THREAD_COUNT
+ " allocation threads");
while (WB.g1NumFreeRegions() > freeRegionLeft) {
try {
humongousAllocations.add(new byte[HUMONGOUS_SIZES[RND.nextInt(HUMONGOUS_SIZES.length)]]);
} catch (OutOfMemoryError oom) {
//We got OOM trying to fill heap with humongous objects
//It probably means that heap is fragmented which is strange since the test logic should avoid it
System.out.println("Warning: OOM while allocating humongous objects - it likely means "
+ "that heap is fragmented");
break;
}
}
System.out.println("Initial free regions " + initialFreeRegionsCount + "; Free regions left "
+ WB.g1NumFreeRegions());
LinkedList<Thread> threads = new LinkedList<>();
for (int i = 0; i < ALLOC_THREAD_COUNT; i++) {
threads.add(new Thread(new Allocator(maxMemoryPerAllocThread)));
}
threads.stream().forEach(Thread::start);
while ((System.currentTimeMillis() - startTime < duration) && error == null) {
Thread.yield();
}
shouldStop = true;
System.out.println("Finished test");
if (error != null) {
throw error;
}
}
}

@ -138,6 +138,41 @@ public enum GC {
}
},
MIXED_GC {
@Override
public Runnable get() {
return () -> {
WHITE_BOX.youngGC();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
WHITE_BOX.youngGC();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
WHITE_BOX.g1StartConcMarkCycle();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
WHITE_BOX.youngGC();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
// Provoking Mixed GC
WHITE_BOX.youngGC();// second evacuation pause will be mixed
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
};
}
public Consumer<ReferenceInfo<Object[]>> getChecker() {
return getCheckerImpl(true, false, true, false);
}
@Override
public List<String> shouldContain() {
return Arrays.asList(GCTokens.WB_INITIATED_CMC);
}
@Override
public List<String> shouldNotContain() {
return Arrays.asList(GCTokens.YOUNG_GC);
}
},
FULL_GC_MEMORY_PRESSURE {
@Override
public Runnable get() {

@ -38,6 +38,9 @@ The test checks that after different type of GC unreachable objects behave as ex
non-humongous and humongous objects are not collected since we make 2 Young GC to promote all
weak references to Old Gen.
6. Mixed GC - weakly referenced non-humongous and humongous objects are collected, softly referenced non-humongous and
humongous objects are not collected.
The test gets gc type as a command line argument.
Then the test allocates object graph in heap (currently testing scenarios are pre-generated and stored in
TestcaseData.getPregeneratedTestcases()) with TestObjectGraphAfterGC::allocateObjectGraph.

@ -66,6 +66,12 @@ import java.util.stream.Collectors;
* sun.hotspot.WhiteBox$WhiteBoxPermission
*
* @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=30000 -XX:G1MixedGCLiveThresholdPercent=100 -XX:G1HeapWastePercent=0
* -XX:G1HeapRegionSize=1M -Xlog:gc=info:file=TestObjectGraphAfterGC_MIXED_GC.gc.log -XX:MaxTenuringThreshold=1
* -XX:G1MixedGCCountTarget=1 -XX:G1OldCSetRegionThresholdPercent=100 -XX:SurvivorRatio=1 -XX:InitiatingHeapOccupancyPercent=0
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC MIXED_GC
*
* @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xlog:gc*=debug:file=TestObjectGraphAfterGC_YOUNG_GC.gc.log
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC YOUNG_GC
*

@ -0,0 +1,71 @@
/*
* Copyright (c) 2016, 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 "runtime/arguments.hpp"
#include "unittest.hpp"
#include "utilities/globalDefinitions.hpp"
TEST(arguments, atojulong) {
char ullong_max[32];
int ret = jio_snprintf(ullong_max, sizeof(ullong_max), JULONG_FORMAT, ULLONG_MAX);
ASSERT_NE(-1, ret);
julong value;
const char* invalid_strings[] = {
"", "-1", "-100", " 1", "2 ", "3 2", "1.0",
"0x4.5", "0x", "0x0x1" "0.001", "4e10", "e"
"K", "M", "G", "1MB", "1KM", "AA", "0B",
"18446744073709551615K", "17179869184G",
"999999999999999999999999999999"
};
for (uint i = 0; i < ARRAY_SIZE(invalid_strings); i++) {
ASSERT_FALSE(Arguments::atojulong(invalid_strings[i], &value))
<< "Invalid string '" << invalid_strings[i] << "' parsed without error.";
}
struct {
const char* str;
julong expected_value;
} valid_strings[] = {
{ "0", 0 },
{ "4711", 4711 },
{ "1K", 1ULL * K },
{ "1k", 1ULL * K },
{ "2M", 2ULL * M },
{ "2m", 2ULL * M },
{ "4G", 4ULL * G },
{ "4g", 4ULL * G },
{ "0K", 0 },
{ ullong_max, ULLONG_MAX },
{ "0xcafebabe", 0xcafebabe },
{ "0XCAFEBABE", 0xcafebabe },
{ "0XCAFEbabe", 0xcafebabe },
{ "0x10K", 0x10 * K }
};
for (uint i = 0; i < ARRAY_SIZE(valid_strings); i++) {
ASSERT_TRUE(Arguments::atojulong(valid_strings[i].str, &value))
<< "Valid string '" << valid_strings[i].str << "' did not parse.";
ASSERT_EQ(valid_strings[i].expected_value, value);
}
}

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, 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.
*/
/* Recoded in jasm to provoke an ICCE assigning a non-static final field with putstatic.
class Bad {
public static final int i; //rewritten
//rewritten to: public final int i;
static { i = 5; } // putstatic instruction
}
*/
super class Bad
version 53:0
{
// Remove 'static' keyword
public final Field i:I;
Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
static Method "<clinit>":"()V"
stack 1 locals 0
{
iconst_5;
putstatic Field i:"I";
return;
}
} // end Class Bad

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016, 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 PutfieldError
* @bug 8160551
* @summary Throw ICCE rather than crashing for nonstatic final field in static initializer
* @compile Bad.jasm
* @run main PutfieldError
*/
public class PutfieldError {
public static void main(java.lang.String[] unused) {
try {
Bad b = new Bad();
System.out.println("Bad.i = " + 5);
throw new RuntimeException("ICCE NOT thrown as expected");
} catch (IncompatibleClassChangeError icce) {
System.out.println("ICCE thrown as expected");
}
}
}

@ -0,0 +1,72 @@
/*
* Copyright (c) 2016, 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 SharedStringsDedup
* @summary Test -Xshare:auto with shared strings and -XX:+UseStringDeduplication
* Feature support: G1GC only, compressed oops/kptrs, 64-bit os, not on windows
* @requires (sun.arch.data.model != "32") & (os.family != "windows")
* @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
* @requires vm.gc.G1
* @library /testlibrary
* @modules java.base/jdk.internal.misc
* java.management
* @run main SharedStringsDedup
*/
import jdk.test.lib.*;
import java.io.File;
// The main purpose is to test the interaction between shared strings
// and -XX:+UseStringDeduplication. We run in -Xshare:auto mode so
// we don't need to worry about CDS archive mapping failure (which
// doesn't happen often so it won't impact coverage).
public class SharedStringsDedup {
public static void main(String[] args) throws Exception {
// Dump
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:+UnlockDiagnosticVMOptions",
"-XX:SharedArchiveFile=./SharedStringsDedup.jsa",
"-XX:+UseCompressedOops", "-XX:+UseG1GC",
"-XX:+PrintSharedSpaces",
"-Xshare:dump");
new OutputAnalyzer(pb.start())
.shouldContain("Loading classes to share")
.shouldContain("Shared string table stats")
.shouldHaveExitValue(0);
// Run with -Xshare:auto
pb = ProcessTools.createJavaProcessBuilder(
"-XX:+UnlockDiagnosticVMOptions",
"-XX:SharedArchiveFile=./SharedStringsDedup.jsa",
"-XX:+UseCompressedOops", "-XX:+UseG1GC",
"-XX:+UseStringDeduplication",
"-Xshare:auto",
"-version");
new OutputAnalyzer(pb.start())
.shouldMatch("(java|openjdk) version")
.shouldHaveExitValue(0);
}
}

@ -0,0 +1,35 @@
/*
* Copyright (c) 2016, 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.
*/
/**
* A custom system ClassLoader to define the module "m2" to during iterations of
* differing test runs within the test ModuleStress.java
*/
public class CustomSystemClassLoader extends ClassLoader {
public CustomSystemClassLoader() {
super();
}
public CustomSystemClassLoader(ClassLoader parent) {
super(parent);
}
}

@ -0,0 +1,129 @@
/*
* Copyright (c) 2016, 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.
*/
import static jdk.test.lib.Asserts.*;
import java.lang.reflect.Layer;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
//
// ClassLoader1 --> defines m1 --> packages p1
// ClassLoader2 --> defines m2 --> packages p2
// Java System Class Loader --> defines m3 --> packages p3
//
// m1 can read m2
// package p2 in m2 is exported to m1 and m3
//
// class p1.c1 defined in m1 tries to access p2.c2 defined in m2
// Access allowed since m1 can read m2 and package p2 is exported to m1.
//
public class ModuleNonBuiltinCLMain {
// Create a Layer over the boot layer.
// Define modules within this layer to test access between
// publically defined classes within packages of those modules.
public void createLayerOnBoot() throws Throwable {
// Define module: m1
// Can read: java.base, m2
// Packages: p1
// Packages exported: p1 is exported to unqualifiedly
ModuleDescriptor descriptor_m1 =
new ModuleDescriptor.Builder("m1")
.requires("java.base")
.requires("m2")
.exports("p1")
.build();
// Define module: m2
// Can read: java.base, m3
// Packages: p2
// Packages exported: package p2 is exported to m1 and m3
Set<String> targets = new HashSet<>();
targets.add("m1");
targets.add("m3");
ModuleDescriptor descriptor_m2 =
new ModuleDescriptor.Builder("m2")
.requires("java.base")
.requires("m3")
.exports("p2", targets)
.build();
// Define module: m3
// Can read: java.base
// Packages: p3
// Packages exported: none
ModuleDescriptor descriptor_m3 =
new ModuleDescriptor.Builder("m3")
.requires("java.base")
.build();
// Set up a ModuleFinder containing all modules for this layer.
ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3);
// Resolves "m1"
Configuration cf = Layer.boot()
.configuration()
.resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
// map each module to differing user defined class loaders for this test
Map<String, ClassLoader> map = new HashMap<>();
Loader1 cl1 = new Loader1();
Loader2 cl2 = new Loader2();
ClassLoader cl3 = ClassLoader.getSystemClassLoader();
map.put("m1", cl1);
map.put("m2", cl2);
map.put("m3", cl3);
// Create Layer that contains m1 & m2
Layer layer = Layer.boot().defineModules(cf, map::get);
assertTrue(layer.findLoader("m1") == cl1);
assertTrue(layer.findLoader("m2") == cl2);
assertTrue(layer.findLoader("m3") == cl3);
assertTrue(layer.findLoader("java.base") == null);
// now use the same loader to load class p1.c1
Class p1_c1_class = cl1.loadClass("p1.c1");
try {
p1_c1_class.newInstance();
} catch (IllegalAccessError e) {
throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1");
}
}
public static void main(String args[]) throws Throwable {
ModuleNonBuiltinCLMain test = new ModuleNonBuiltinCLMain();
test.createLayerOnBoot();
}
static class Loader1 extends ClassLoader { }
static class Loader2 extends ClassLoader { }
}

@ -0,0 +1,109 @@
/*
* Copyright (c) 2016, 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.
*/
import static jdk.test.lib.Asserts.*;
import java.lang.reflect.Layer;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//
// ClassLoader1 --> defines m1 --> packages p1
// ClassLoader1 --> defines m2 --> packages p2
//
// m1 can read m2
// package p2 in m2 is exported to m1
//
// class p1.c1 defined in m1 tries to access p2.c2 defined in m2
// Access allowed since m1 can read m2 and package p2 is exported to m1.
//
public class ModuleSameCLMain {
// Create a Layer over the boot layer.
// Define modules within this layer to test access between
// publically defined classes within packages of those modules.
public void createLayerOnBoot() throws Throwable {
// Define module: m1
// Can read: java.base, m2
// Packages: p1
// Packages exported: p1 is exported to unqualifiedly
ModuleDescriptor descriptor_m1 =
new ModuleDescriptor.Builder("m1")
.requires("java.base")
.requires("m2")
.exports("p1")
.build();
// Define module: m2
// Can read: java.base
// Packages: p2
// Packages exported: package p2 is exported to m1
ModuleDescriptor descriptor_m2 =
new ModuleDescriptor.Builder("m2")
.requires("java.base")
.exports("p2", "m1")
.build();
// Set up a ModuleFinder containing all modules for this layer.
ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2);
// Resolves "m1"
Configuration cf = Layer.boot()
.configuration()
.resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
// map each module to the same class loader for this test
Map<String, ClassLoader> map = new HashMap<>();
Loader1 cl1 = new Loader1();
map.put("m1", cl1);
map.put("m2", cl1);
// Create Layer that contains m1 & m2
Layer layer = Layer.boot().defineModules(cf, map::get);
assertTrue(layer.findLoader("m1") == cl1);
assertTrue(layer.findLoader("m2") == cl1);
assertTrue(layer.findLoader("java.base") == null);
// now use the same loader to load class p1.c1
Class p1_c1_class = cl1.loadClass("p1.c1");
try {
p1_c1_class.newInstance();
} catch (IllegalAccessError e) {
throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1");
}
}
public static void main(String args[]) throws Throwable {
ModuleSameCLMain test = new ModuleSameCLMain();
test.createLayerOnBoot();
}
static class Loader1 extends ClassLoader { }
}

@ -0,0 +1,131 @@
/*
* Copyright (c) 2016, 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.
*/
/*
* @test
* @bug 8159262
* @summary Test differing scenarios where a module's readability list and a package's exportability list should be walked
* @modules java.base/jdk.internal.misc
* @library /testlibrary /test/lib
* @compile ../AccessCheck/ModuleLibrary.java
* @compile ModuleSameCLMain.java
* @compile ModuleNonBuiltinCLMain.java
* @compile CustomSystemClassLoader.java
* @build ModuleStress
* @run main/othervm ModuleStress
*/
import jdk.test.lib.*;
import java.io.File;
public class ModuleStress {
public static void main(String[] args) throws Exception {
// Test #1: java -version
// All modules' readability lists and packages' exportability
// lists should contain only modules defined to the 3 builtin
// loaders (boot, application, platform). Thus there is
// not a need to walk those lists at a GC safepoint since
// those loaders never die.
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"-version");
OutputAnalyzer oa = new OutputAnalyzer(pb.start());
oa.shouldNotContain("must be walked")
.shouldNotContain("being walked")
.shouldHaveExitValue(0);
// Next 2 tests involve the use of class p1.c1 and p2.c2
String source1 = "package p1;" +
"import p2.c2;" +
"public class c1 {" +
" public c1() {" +
" p2.c2 c2_obj = new p2.c2();" +
" c2_obj.method2();" +
" }" +
"}";
String source2 = "package p2;" +
"public class c2 {" +
" public void method2() { }" +
"}";
ClassFileInstaller.writeClassToDisk("p2/c2",
InMemoryJavaCompiler.compile("p2.c2", source2), System.getProperty("test.classes"));
ClassFileInstaller.writeClassToDisk("p1/c1",
InMemoryJavaCompiler.compile("p1.c1", source1), System.getProperty("test.classes"));
// Test #2: Load two modules defined to the same customer class loader.
// m1's module readability list and package p2's exportability should
// not be walked at a GC safepoint since both modules are defined to
// the same loader and thus have the exact same life cycle.
pb = ProcessTools.createJavaProcessBuilder(
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"ModuleSameCLMain");
oa = new OutputAnalyzer(pb.start());
oa.shouldNotContain("must be walked")
.shouldNotContain("being walked")
.shouldHaveExitValue(0);
// Test #3: Load two modules in differing custom class loaders.
// m1's module readability list and package p2's exportability list must
// be walked at a GC safepoint since both modules are defined to non-builtin
// class loaders which could die and thus be unloaded.
pb = ProcessTools.createJavaProcessBuilder(
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"ModuleNonBuiltinCLMain");
oa = new OutputAnalyzer(pb.start());
oa.shouldContain("module m1 reads list must be walked")
.shouldContain("package p2 defined in module m2, exports list must be walked")
.shouldNotContain("module m2 reads list must be walked")
.shouldHaveExitValue(0);
// Test #4: Load two modules in differing custom class loaders,
// of which one has been designated as the custom system class loader
// via -Djava.system.class.loader=CustomSystemClassLoader. Since
// m3 is defined to the system class loader, m2's module readability
// list does not have to be walked at a GC safepoint, but package p2's
// exportability list does.
pb = ProcessTools.createJavaProcessBuilder(
"-Djava.system.class.loader=CustomSystemClassLoader",
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"ModuleNonBuiltinCLMain");
oa = new OutputAnalyzer(pb.start());
oa.shouldContain("package p2 defined in module m2, exports list must be walked")
.shouldNotContain("module m2 reads list must be walked")
.shouldHaveExitValue(0);
}
}

@ -0,0 +1,84 @@
/*
* Copyright (c) 2016, 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 8159262
* @summary layers over the boot layer are repeatedly created, during this iteration, GCs are forced to verify correct walk of module and package lists.
* @modules java.base/jdk.internal.misc
* @library /testlibrary /test/lib
* @compile ../CompilerUtils.java
* @build ModuleStressGC
* @run main/othervm ModuleStressGC
*/
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.*;
public class ModuleStressGC {
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");
/**
* Compile two module definitions used by the test, jdk.test and jdk.translet.
*/
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");
}
// Compile module jdk.translet declaration
compiled = CompilerUtils.compile(
SRC_DIR.resolve("jdk.translet"),
MODS_DIR.resolve("jdk.translet"),
"-XaddExports:jdk.test/test=jdk.translet",
"-mp", MODS_DIR.toString());
if (!compiled) {
throw new RuntimeException("Test failed to compile module jdk.translet");
}
// Sanity check that the test, jdk.test/test/MainGC.java,
// correctly walks module jdk.test's reads list and package
// test's, defined to module jdk.translet, export list at
// GC safepoints.
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Xlog:modules=trace",
"-mp", MODS_DIR.toString(),
"-m", "jdk.test/test.MainGC");
OutputAnalyzer oa = new OutputAnalyzer(pb.start());
oa.shouldContain("package test defined in module jdk.test, exports list being walked")
.shouldContain("module jdk.test reads list being walked")
.shouldHaveExitValue(0);
}
}

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016, 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;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.lang.reflect.Layer;
import java.lang.reflect.Method;
import java.lang.reflect.Module;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MainGC {
private static final Path MODS_DIR = Paths.get(System.getProperty("jdk.module.path"));
static final String MODULE_NAME = "jdk.translet";
public static void main(String[] args) throws Exception {
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
Layer layerBoot = Layer.boot();
Configuration cf = layerBoot
.configuration()
.resolveRequires(ModuleFinder.of(), finder, Set.of(MODULE_NAME));
Module testModule = MainGC.class.getModule();
ClassLoader scl = ClassLoader.getSystemClassLoader();
// Create an unique module/class loader in a layer above the boot layer.
// Export this module to the jdk.test/test package.
// Add a read edge from module jdk.test to this module.
Callable<Void> task = new Callable<Void>() {
@Override
public Void call() throws Exception {
Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
Module transletModule = layer.findModule(MODULE_NAME).get();
testModule.addExports("test", transletModule);
testModule.addReads(transletModule);
Class<?> c = layer.findLoader(MODULE_NAME).loadClass("translet.MainGC");
Method method = c.getDeclaredMethod("go");
method.invoke(null);
return null;
}
};
List<Future<Void>> results = new ArrayList<>();
// Repeatedly create the layer above stressing the exportation of
// package jdk.test/test to several different modules.
ExecutorService pool = Executors.newFixedThreadPool(Math.min(100, Runtime.getRuntime().availableProcessors()*10));
try {
for (int i = 0; i < 10000; i++) {
results.add(pool.submit(task));
// At specified intervals, force a GC. This provides an
// opportunity to verify that both the module jdk.test's reads
// and the package test's, which is defined to jdk.test, exports
// lists are being walked.
if (i == 3000 || i == 6000 || i == 9000) {
System.gc();
}
}
} finally {
pool.shutdown();
}
int passed = 0;
int failed = 0;
// The failed state should be 0, the created modules in layers above the
// boot layer should be allowed access to the contents of the jdk.test/test
// package since that package was exported to the transletModule above.
for (Future<Void> result : results) {
try {
result.get();
passed++;
} catch (Throwable x) {
x.printStackTrace();
failed++;
}
}
System.out.println("passed: " + passed);
System.out.println("failed: " + failed);
}
public static void callback() { }
}

@ -0,0 +1,30 @@
/*
* Copyright (c) 2016, 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 translet;
public class MainGC {
public static void go() {
test.MainGC.callback();
}
}