--- a/hotspot/make/gensrc/GensrcDtrace.gmk Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/make/gensrc/GensrcDtrace.gmk Thu Jul 14 16:21:57 2016 +0000
@@ -45,7 +45,8 @@
$(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:
--- a/hotspot/make/lib/CompileDtracePostJvm.gmk Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/make/lib/CompileDtracePostJvm.gmk Thu Jul 14 16:21:57 2016 +0000
@@ -68,7 +68,7 @@
$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
--- a/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrap.java Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/UncommonTrap.java Thu Jul 14 16:21:57 2016 +0000
@@ -16,9 +16,9 @@
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
*
*/
package com.sun.hotspot.tools.compiler;
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -501,13 +501,26 @@
}
}
-/**
- * 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 @@
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 @@
}
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();
}
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Thu Jul 14 16:21:57 2016 +0000
@@ -270,7 +270,9 @@
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.
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -248,7 +248,7 @@
} 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;
}
}
--- a/hotspot/src/share/vm/classfile/moduleEntry.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -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 @@
// 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 @@
// 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 @@
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 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 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.");
}
--- a/hotspot/src/share/vm/classfile/moduleEntry.hpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp Thu Jul 14 16:21:57 2016 +0000
@@ -43,6 +43,7 @@
// 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 @@
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 @@
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(); }
--- a/hotspot/src/share/vm/classfile/modules.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/modules.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -113,7 +113,7 @@
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 @@
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;
--- a/hotspot/src/share/vm/classfile/packageEntry.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/packageEntry.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -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 @@
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 @@
// 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 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()));
--- a/hotspot/src/share/vm/classfile/packageEntry.hpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/packageEntry.hpp Thu Jul 14 16:21:57 2016 +0000
@@ -69,6 +69,7 @@
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 @@
_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 @@
// 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();
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -175,9 +175,18 @@
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;
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Jul 14 16:21:57 2016 +0000
@@ -660,6 +660,7 @@
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:
--- a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -48,10 +48,10 @@
#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
--- a/hotspot/src/share/vm/interpreter/rewriter.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/interpreter/rewriter.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -419,21 +419,20 @@
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);
}
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -584,27 +584,26 @@
// 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.
--- a/hotspot/src/share/vm/utilities/vmError.cpp Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -205,16 +205,39 @@
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.");
}
--- a/hotspot/test/TEST.groups Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/test/TEST.groups Thu Jul 14 16:21:57 2016 +0000
@@ -395,6 +395,17 @@
: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.
#
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/humongousObjects/TestNoAllocationsInHRegions.java Thu Jul 14 16:21:57 2016 +0000
@@ -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;
+ }
+ }
+}
--- a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/GC.java Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/GC.java Thu Jul 14 16:21:57 2016 +0000
@@ -138,6 +138,41 @@
}
},
+ 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() {
--- a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/README Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/README Thu Jul 14 16:21:57 2016 +0000
@@ -38,6 +38,9 @@
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.
--- a/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java Thu Jul 14 15:47:44 2016 +0000
+++ b/hotspot/test/gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java Thu Jul 14 16:21:57 2016 +0000
@@ -66,6 +66,12 @@
* 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
*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/native/runtime/test_arguments.cpp Thu Jul 14 16:21:57 2016 +0000
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/Bad.jasm Thu Jul 14 16:21:57 2016 +0000
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/PutfieldError.java Thu Jul 14 16:21:57 2016 +0000
@@ -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");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/SharedStringsDedup.java Thu Jul 14 16:21:57 2016 +0000
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ModuleStress/CustomSystemClassLoader.java Thu Jul 14 16:21:57 2016 +0000
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ModuleStress/ModuleNonBuiltinCLMain.java Thu Jul 14 16:21:57 2016 +0000
@@ -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 { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ModuleStress/ModuleSameCLMain.java Thu Jul 14 16:21:57 2016 +0000
@@ -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 { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ModuleStress/ModuleStress.java Thu Jul 14 16:21:57 2016 +0000
@@ -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);
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ModuleStress/ModuleStressGC.java Thu Jul 14 16:21:57 2016 +0000
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ModuleStress/src/jdk.test/test/MainGC.java Thu Jul 14 16:21:57 2016 +0000
@@ -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() { }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ModuleStress/src/jdk.translet/translet/MainGC.java Thu Jul 14 16:21:57 2016 +0000
@@ -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();
+ }
+}