8152404: Stabilize PackageEntry::package_exports_do
Summary: Re-defined PackageEntry member variables and export checking functions
Reviewed-by: dholmes, hseigel
--- a/hotspot/src/share/vm/classfile/packageEntry.cpp Thu Jun 02 09:44:41 2016 +0200
+++ b/hotspot/src/share/vm/classfile/packageEntry.cpp Fri Jun 03 11:53:55 2016 -0400
@@ -34,15 +34,13 @@
#include "utilities/hashtable.inline.hpp"
#include "utilities/ostream.hpp"
-// Return true if this package is exported to m.
+// Returns true if this package specifies m as a qualified export, including through an unnamed export
bool PackageEntry::is_qexported_to(ModuleEntry* m) const {
assert(m != NULL, "No module to lookup in this package's qualified exports list");
MutexLocker m1(Module_lock);
- if (!_is_exported) {
- return false;
- } else if (_is_exported_allUnnamed && !m->is_named()) {
+ if (is_exported_allUnnamed() && !m->is_named()) {
return true;
- } else if (_qualified_exports == NULL) {
+ } else if (!has_qual_exports_list()) {
return false;
} else {
return _qualified_exports->contains(m);
@@ -52,8 +50,7 @@
// Add a module to the package's qualified export list.
void PackageEntry::add_qexport(ModuleEntry* m) {
assert_locked_or_safepoint(Module_lock);
- assert(_is_exported == true, "Adding a qualified export to a package that is not exported");
- if (_qualified_exports == NULL) {
+ 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 =
@@ -62,7 +59,7 @@
_qualified_exports->append_if_missing(m);
}
-// Set the package's exported state based on the value of the ModuleEntry.
+// Set the package's exported states based on the value of the ModuleEntry.
void PackageEntry::set_exported(ModuleEntry* m) {
MutexLocker m1(Module_lock);
if (is_unqual_exported()) {
@@ -73,7 +70,7 @@
if (m == NULL) {
// NULL indicates the package is being unqualifiedly exported
- if (_is_exported && _qualified_exports != NULL) {
+ if (has_qual_exports_list()) {
// Legit to transition a package from being qualifiedly exported
// to unqualified. Clean up the qualified lists at the next
// safepoint.
@@ -85,11 +82,17 @@
} else {
// Add the exported module
- _is_exported = true;
add_qexport(m);
}
}
+void PackageEntry::set_is_exported_allUnnamed() {
+ MutexLocker m1(Module_lock);
+ if (!is_unqual_exported()) {
+ _is_exported_allUnnamed = true;
+ }
+}
+
// Remove dead module entries within the package's exported list.
void PackageEntry::purge_qualified_exports() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
@@ -170,7 +173,7 @@
if (!module->is_named()) {
// Set the exported state to true because all packages
// within the unnamed module are unqualifiedly exported
- entry->set_exported(true);
+ entry->set_unqual_exported();
}
entry->set_module(module);
return entry;
@@ -248,6 +251,20 @@
}
+// iteration of qualified exports
+void PackageEntry::package_exports_do(ModuleClosure* const f) {
+ assert_locked_or_safepoint(Module_lock);
+ assert(f != NULL, "invariant");
+
+ if (has_qual_exports_list()) {
+ int qe_len = _qualified_exports->length();
+
+ for (int i = 0; i < qe_len; ++i) {
+ f->do_module(_qualified_exports->at(i));
+ }
+ }
+}
+
// Remove dead entries from all packages' exported list
void PackageEntryTable::purge_all_package_exports() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
@@ -281,10 +298,10 @@
void PackageEntry::print(outputStream* st) {
ResourceMark rm;
st->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index "
- INT32_FORMAT " is_exported %d is_exported_allUnnamed %d " "next "PTR_FORMAT,
+ 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, _is_exported_allUnnamed, p2i(next()));
+ _classpath_index, _is_exported_unqualified, _is_exported_allUnnamed, p2i(next()));
}
void PackageEntryTable::verify() {
@@ -305,17 +322,3 @@
void PackageEntry::verify() {
guarantee(name() != NULL, "A package entry must have a corresponding symbol name.");
}
-
-// iteration of qualified exports
-void PackageEntry::package_exports_do(ModuleClosure* const f) {
- assert_locked_or_safepoint(Module_lock);
- assert(f != NULL, "invariant");
-
- if (is_qual_exported()) {
- int qe_len = _qualified_exports->length();
-
- for (int i = 0; i < qe_len; ++i) {
- f->do_module(_qualified_exports->at(i));
- }
- }
-}
--- a/hotspot/src/share/vm/classfile/packageEntry.hpp Thu Jun 02 09:44:41 2016 +0200
+++ b/hotspot/src/share/vm/classfile/packageEntry.hpp Fri Jun 03 11:53:55 2016 -0400
@@ -34,16 +34,32 @@
// A PackageEntry basically represents a Java package. It contains:
// - Symbol* containing the package's name.
// - ModuleEntry* for this package's containing module.
-// - a flag indicating if package is exported, either qualifiedly or
-// unqualifiedly.
+// - a flag indicating if package is exported unqualifiedly
// - a flag indicating if this package is exported to all unnamed modules.
// - a growable array containing other module entries that this
// package is exported to.
//
-// Packages that are:
-// - not exported: _qualified_exports = NULL && _is_exported is false
-// - qualified exports: (_qualified_exports != NULL || _is_exported_allUnnamed is true) && _is_exported is true
-// - unqualified exports: (_qualified_exports = NULL && _is_exported_allUnnamed is false) && _is_exported is true
+// Packages can be exported in the following 3 ways:
+// - not exported: the package has not been explicitly qualified to a
+// particular module nor has it been specified to be
+// unqualifiedly exported to all modules. If all states
+// of exportedness are false, the package is considered
+// not exported.
+// - qualified exports: the package has been explicitly qualified to at least
+// one particular module or has been qualifiedly exported
+// to all unnamed modules.
+// Note: _is_exported_allUnnamed is a form of a qualified
+// export. It is equivalent to the package being
+// explicitly exported to all current and future unnamed modules.
+// - unqualified exports: the package is exported to all modules.
+//
+// A package can transition from:
+// - being not exported, to being exported either in a qualified or unqualified manner
+// - being qualifiedly exported, to unqualifiedly exported. Its exported scope is widened.
+//
+// A package cannot transition from:
+// - being unqualifiedly exported, to exported qualifiedly to a specific module.
+// This transition attempt is silently ignored in set_exported.
//
// The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either
// data structure.
@@ -55,7 +71,7 @@
// loaded by the boot loader from -Xbootclasspath/a in an unnamed module, it
// indicates from which class path entry.
s2 _classpath_index;
- bool _is_exported;
+ bool _is_exported_unqualified;
bool _is_exported_allUnnamed;
GrowableArray<ModuleEntry*>* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint
GrowableArray<ModuleEntry*>* _qualified_exports;
@@ -68,7 +84,7 @@
void init() {
_module = NULL;
_classpath_index = -1;
- _is_exported = false;
+ _is_exported_unqualified = false;
_is_exported_allUnnamed = false;
_exported_pending_delete = NULL;
_qualified_exports = NULL;
@@ -83,34 +99,41 @@
void set_module(ModuleEntry* m) { _module = m; }
// package's export state
- bool is_exported() const { return _is_exported; } // qualifiedly or unqualifiedly exported
+ bool is_exported() const { // qualifiedly or unqualifiedly exported
+ return (is_unqual_exported() || has_qual_exports_list() || is_exported_allUnnamed());
+ }
+ // Returns true if the package has any explicit qualified exports or is exported to all unnamed
bool is_qual_exported() const {
- return (_is_exported && (_qualified_exports != NULL || _is_exported_allUnnamed));
+ return (has_qual_exports_list() || is_exported_allUnnamed());
+ }
+ // Returns true if there are any explicit qualified exports
+ bool has_qual_exports_list() const {
+ assert(!(_qualified_exports != NULL && _is_exported_unqualified),
+ "_qualified_exports set at same time as _is_exported_unqualified");
+ return (_qualified_exports != NULL);
+ }
+ bool is_exported_allUnnamed() const {
+ assert(!(_is_exported_allUnnamed && _is_exported_unqualified),
+ "_is_exported_allUnnamed set at same time as _is_exported_unqualified");
+ return _is_exported_allUnnamed;
}
bool is_unqual_exported() const {
- return (_is_exported && (_qualified_exports == NULL && !_is_exported_allUnnamed));
+ assert(!(_qualified_exports != NULL && _is_exported_unqualified),
+ "_qualified_exports set at same time as _is_exported_unqualified");
+ assert(!(_is_exported_allUnnamed && _is_exported_unqualified),
+ "_is_exported_allUnnamed set at same time as _is_exported_unqualified");
+ return _is_exported_unqualified;
}
void set_unqual_exported() {
- _is_exported = true;
+ _is_exported_unqualified = true;
_is_exported_allUnnamed = false;
_qualified_exports = NULL;
}
bool exported_pending_delete() const { return (_exported_pending_delete != NULL); }
- void set_exported(bool e) { _is_exported = e; }
void set_exported(ModuleEntry* m);
- void set_is_exported_allUnnamed() {
- if (!is_unqual_exported()) {
- _is_exported_allUnnamed = true;
- _is_exported = true;
- }
- }
- bool is_exported_allUnnamed() const {
- assert(_is_exported || !_is_exported_allUnnamed,
- "is_allUnnamed set without is_exported being set");
- return _is_exported_allUnnamed;
- }
+ void set_is_exported_allUnnamed();
void set_classpath_index(s2 classpath_index) {
_classpath_index = classpath_index;
@@ -122,7 +145,7 @@
// returns true if the package is defined in the unnamed module
bool in_unnamed_module() const { return !_module->is_named(); }
- // returns true if the package specifies m as a qualified export
+ // returns true if the package specifies m as a qualified export, including through an unnamed export
bool is_qexported_to(ModuleEntry* m) const;
// add the module to the package's qualified exports