mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
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:
parent
007b0fa3db
commit
f30fc1c88b
297 changed files with 15848 additions and 2302 deletions
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue