8142968: Module System implementation

Initial integration of JEP 200, JEP 260, JEP 261, and JEP 282

Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com>
Co-authored-by: Karen Kinnear <karen.kinnear@oracle.com>
Co-authored-by: Mandy Chung <mandy.chung@oracle.com>
Co-authored-by: Mark Reinhold <mark.reinhold@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: Calvin Cheung <calvin.cheung@oracle.com>
Co-authored-by: Christian Tornqvist <christian.tornqvist@oracle.com>
Co-authored-by: Erik Joelsson <erik.joelsson@oracle.com>
Co-authored-by: George Triantafillou <george.triantafillou@oracle.com>
Co-authored-by: Igor Ignatyev <igor.ignatyev@oracle.com>
Co-authored-by: Ioi Lam <ioi.lam@oracle.com>
Co-authored-by: James Laskey <james.laskey@oracle.com>
Co-authored-by: Jean-Francois Denise <jean-francois.denise@oracle.com>
Co-authored-by: Jiangli Zhou <jiangli.zhou@oracle.com>
Co-authored-by: Markus Gronlund <markus.gronlund@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Staffan Larsen <staffan.larsen@oracle.com>
Co-authored-by: Sundararajan Athijegannathan <sundararajan.athijegannathan@oracle.com>
Reviewed-by: acorn, ccheung, coleenp, ctornqvi, dholmes, dsimms, gtriantafill, iklam, jiangli, mgronlun, mseledtsov, cjplummer, sspitsyn, stefank, twisti, hseigel, lfoltan, alanb, mchung, dfazunen
This commit is contained in:
Alan Bateman 2016-03-17 19:04:01 +00:00
parent 007b0fa3db
commit f30fc1c88b
297 changed files with 15848 additions and 2302 deletions

View file

@ -24,6 +24,8 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
@ -452,25 +454,193 @@ static bool can_relax_access_check_for(const Klass* accessor,
return false;
}
bool Reflection::verify_class_access(const Klass* current_class,
const Klass* new_class,
bool classloader_only) {
/*
Type Accessibility check for public types: Callee Type T is accessible to Caller Type S if:
Callee T in Callee T in package PT,
unnamed module runtime module MT
------------------------------------------------------------------------------------------------
Caller S in package If MS is loose: YES If same classloader/package (PS == PT): YES
PS, runtime module MS If MS can read T's If same runtime module: (MS == MT): YES
unnamed module: YES
Else if (MS can read MT (Establish readability) &&
MT exports PT to MS or to all modules): YES
------------------------------------------------------------------------------------------------
Caller S in unnamed YES Readability exists because unnamed module
module UM "reads" all modules
if (MT exports PT to UM or to all modules): YES
------------------------------------------------------------------------------------------------
Note: a loose module is a module that can read all current and future unnamed modules.
*/
Reflection::VerifyClassAccessResults Reflection::verify_class_access(
const Klass* current_class, const Klass* new_class, bool classloader_only) {
// Verify that current_class can access new_class. If the classloader_only
// flag is set, we automatically allow any accesses in which current_class
// doesn't have a classloader.
if ((current_class == NULL) ||
(current_class == new_class) ||
(new_class->is_public()) ||
is_same_class_package(current_class, new_class)) {
return true;
return ACCESS_OK;
}
// Allow all accesses from sun/reflect/MagicAccessorImpl subclasses to
// succeed trivially.
if (current_class->is_subclass_of(SystemDictionary::reflect_MagicAccessorImpl_klass())) {
return true;
return ACCESS_OK;
}
return can_relax_access_check_for(current_class, new_class, classloader_only);
// module boundaries
if (new_class->is_public()) {
// Ignore modules for DumpSharedSpaces because we do not have any package
// or module information for modules other than java.base.
if (DumpSharedSpaces) {
return ACCESS_OK;
}
// Find the module entry for current_class, the accessor
ModuleEntry* module_from = InstanceKlass::cast(current_class)->module();
// Find the module entry for new_class, the accessee
if (new_class->is_objArray_klass()) {
new_class = ObjArrayKlass::cast(new_class)->bottom_klass();
}
if (!new_class->is_instance_klass()) {
// Everyone can read a typearray.
assert (new_class->is_typeArray_klass(), "Unexpected klass type");
return ACCESS_OK;
}
ModuleEntry* module_to = InstanceKlass::cast(new_class)->module();
// both in same (possibly unnamed) module
if (module_from == module_to) {
return ACCESS_OK;
}
// Acceptable access to a type in an unamed module. Note that since
// unnamed modules can read all unnamed modules, this also handles the
// case where module_from is also unnamed but in a different class loader.
if (!module_to->is_named() &&
(module_from->can_read_all_unnamed() || module_from->can_read(module_to))) {
return ACCESS_OK;
}
// Establish readability, check if module_from is allowed to read module_to.
if (!module_from->can_read(module_to)) {
return MODULE_NOT_READABLE;
}
PackageEntry* package_to = InstanceKlass::cast(new_class)->package();
assert(package_to != NULL, "can not obtain new_class' package");
// Once readability is established, if module_to exports T unqualifiedly,
// (to all modules), than whether module_from is in the unnamed module
// or not does not matter, access is allowed.
if (package_to->is_unqual_exported()) {
return ACCESS_OK;
}
// Access is allowed if both 1 & 2 hold:
// 1. Readability, module_from can read module_to (established above).
// 2. Either module_to exports T to module_from qualifiedly.
// or
// module_to exports T to all unnamed modules and module_from is unnamed.
// or
// module_to exports T unqualifiedly to all modules (checked above).
if (!package_to->is_qexported_to(module_from)) {
return TYPE_NOT_EXPORTED;
}
return ACCESS_OK;
}
if (can_relax_access_check_for(current_class, new_class, classloader_only)) {
return ACCESS_OK;
}
return OTHER_PROBLEM;
}
// Return an error message specific to the specified Klass*'s and result.
// This function must be called from within a block containing a ResourceMark.
char* Reflection::verify_class_access_msg(const Klass* current_class,
const Klass* new_class,
VerifyClassAccessResults result) {
assert(result != ACCESS_OK, "must be failure result");
char * msg = NULL;
if (result != OTHER_PROBLEM && new_class != NULL && current_class != NULL) {
// Find the module entry for current_class, the accessor
ModuleEntry* module_from = InstanceKlass::cast(current_class)->module();
const char * module_from_name = module_from->is_named() ? module_from->name()->as_C_string() : UNNAMED_MODULE;
const char * current_class_name = current_class->external_name();
// Find the module entry for new_class, the accessee
ModuleEntry* module_to = NULL;
if (new_class->is_objArray_klass()) {
new_class = ObjArrayKlass::cast(new_class)->bottom_klass();
}
if (new_class->is_instance_klass()) {
module_to = InstanceKlass::cast(new_class)->module();
} else {
module_to = ModuleEntryTable::javabase_module();
}
const char * module_to_name = module_to->is_named() ? module_to->name()->as_C_string() : UNNAMED_MODULE;
const char * new_class_name = new_class->external_name();
if (result == MODULE_NOT_READABLE) {
assert(module_from->is_named(), "Unnamed modules can read all modules");
if (module_to->is_named()) {
size_t len = 100 + strlen(current_class_name) + 2*strlen(module_from_name) +
strlen(new_class_name) + 2*strlen(module_to_name);
msg = NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(msg, len - 1,
"class %s (in module %s) cannot access class %s (in module %s) because module %s does not read module %s",
current_class_name, module_from_name, new_class_name,
module_to_name, module_from_name, module_to_name);
} else {
jobject jlrm = module_to->module();
assert(jlrm != NULL, "Null jlrm in module_to ModuleEntry");
intptr_t identity_hash = JNIHandles::resolve(jlrm)->identity_hash();
size_t len = 160 + strlen(current_class_name) + 2*strlen(module_from_name) +
strlen(new_class_name) + 2*sizeof(uintx);
msg = NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(msg, len - 1,
"class %s (in module %s) cannot access class %s (in unnamed module @" SIZE_FORMAT_HEX ") because module %s does not read unnamed module @" SIZE_FORMAT_HEX,
current_class_name, module_from_name, new_class_name, uintx(identity_hash),
module_from_name, uintx(identity_hash));
}
} else if (result == TYPE_NOT_EXPORTED) {
assert(InstanceKlass::cast(new_class)->package() != NULL,
"Unnamed packages are always exported");
const char * package_name =
InstanceKlass::cast(new_class)->package()->name()->as_klass_external_name();
assert(module_to->is_named(), "Unnamed modules export all packages");
if (module_from->is_named()) {
size_t len = 118 + strlen(current_class_name) + 2*strlen(module_from_name) +
strlen(new_class_name) + 2*strlen(module_to_name) + strlen(package_name);
msg = NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(msg, len - 1,
"class %s (in module %s) cannot access class %s (in module %s) because module %s does not export %s to module %s",
current_class_name, module_from_name, new_class_name,
module_to_name, module_to_name, package_name, module_from_name);
} else {
jobject jlrm = module_from->module();
assert(jlrm != NULL, "Null jlrm in module_from ModuleEntry");
intptr_t identity_hash = JNIHandles::resolve(jlrm)->identity_hash();
size_t len = 170 + strlen(current_class_name) + strlen(new_class_name) +
2*strlen(module_to_name) + strlen(package_name) + 2*sizeof(uintx);
msg = NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(msg, len - 1,
"class %s (in unnamed module @" SIZE_FORMAT_HEX ") cannot access class %s (in module %s) because module %s does not export %s to unnamed module @" SIZE_FORMAT_HEX,
current_class_name, uintx(identity_hash), new_class_name, module_to_name,
module_to_name, package_name, uintx(identity_hash));
}
} else {
ShouldNotReachHere();
}
} // result != OTHER_PROBLEM...
return msg;
}
bool Reflection::verify_field_access(const Klass* current_class,