diff --git a/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties b/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties
index e1ea6f7cb83..2a163b85d1c 100644
--- a/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties
+++ b/jcl/src/java.base/share/classes/com/ibm/oti/util/ExternalMessages-MasterIndex.properties
@@ -1,6 +1,6 @@
/*[INCLUDE-IF]*/
#
-# Copyright (c) 1998, 2019 IBM Corp. and others
+# Copyright (c) 1998, 2020 IBM Corp. and others
#
# This program and the accompanying materials are made available under
# the terms of the Eclipse Public License 2.0 which accompanies this
@@ -397,10 +397,11 @@ K065P=The external parameter types of body: {0} doesn't match the external param
K065Q=The loop body must be non-null
K065R=The requested lookup mode: 0x{0} is not one of the existing access modes: 0x{1}
K065S=Both the requested class and the caller lookup must not be null
-K065T=The target class: {0} must not be a primitive type or an array class
+K065T=The requested class: {0} must not be a void type, primitive type or an array class
K065U=The module: {0} containing the old lookup can't read the module: {1}
K065V=The package: {0} containing the target class is not opened to the module: {1}
-K065W=The access mode: 0x{0} of the caller lookup doesn't have the MODULE mode : 0x{1}
+K065W1=The access mode: 0x{0} of the caller lookup doesn't have the PRIVATE & MODULE mode : 0x{1}
+K065W2=The access mode: 0x{0} of the caller lookup doesn't have the MODULE mode : 0x{1}
K065X=The class byte array must not be null
K065Y1=The access mode: 0x{0} of the lookup class doesn't have the PACKAGE mode: 0x{1}
K065Y2=The class byte array is corrupted
@@ -418,6 +419,7 @@ K0678=Class '{0}' no access to: '{1}'
K0679=Module '{0}' no access to: package '{1}' because module '{0}' can't read module '{2}'
K0680=Class '{0}' no access to: class '{1}'
K0681=Failed to build collector
+K0682=The requested lookup class must not be null
#java.lang.StackWalker
K0639="Stack walker not configured with RETAIN_CLASS_REFERENCE"
diff --git a/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index 36a6c539390..016b2bf03c1 100644
--- a/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jcl/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -169,36 +169,51 @@ static final public class Lookup {
static final int VARARGS = 0x80;
/* single cached value of public Lookup object */
- /*[IF Sidecar19-SE-OpenJ9]
- static Lookup PUBLIC_LOOKUP = new Lookup(Object.class, Lookup.PUBLIC | Lookup.UNCONDITIONAL);
- /*[ELSE]*/
- static Lookup PUBLIC_LOOKUP = new Lookup(Object.class, Lookup.PUBLIC);
- /*[ENDIF] Sidecar19-SE-OpenJ9*/
+ static final int mhMask =
+ /*[IF Java11]*/
+ /*[IF Java14]*/
+ Lookup.UNCONDITIONAL;
+ /*[ELSE] Java14*/
+ Lookup.PUBLIC | Lookup.UNCONDITIONAL;
+ /*[ENDIF] Java14*/
+ /*[ELSE] Java11*/
+ Lookup.PUBLIC;
+ /*[ENDIF] Java11*/
+ static Lookup PUBLIC_LOOKUP = new Lookup(Object.class, mhMask);
/* single cached internal privileged lookup */
static Lookup internalPrivilegedLookup = new Lookup(MethodHandle.class, Lookup.INTERNAL_PRIVILEGED);
static Lookup IMPL_LOOKUP = internalPrivilegedLookup; /* hack for b56 of lambda-dev */
/* Access token used in lookups - Object for public lookup */
+ final Class> prevAccessClass;
final Class> accessClass;
final int accessMode;
private final boolean performSecurityCheck;
- Lookup(Class> lookupClass, int lookupMode, boolean doCheck) {
+ Lookup(Class> lookupClass, Class> prevLookupClass, int lookupMode, boolean doCheck) {
this.performSecurityCheck = doCheck;
if (doCheck && (INTERNAL_PRIVILEGED != lookupMode)) {
- if ( lookupClass.getName().startsWith("java.lang.invoke.")) { //$NON-NLS-1$
+ if (lookupClass.getName().startsWith("java.lang.invoke.")) { //$NON-NLS-1$
/*[MSG "K0588", "Illegal Lookup object - originated from java.lang.invoke: {0}"]*/
throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K0588", lookupClass.getName())); //$NON-NLS-1$
}
}
-
accessClass = lookupClass;
+ prevAccessClass = prevLookupClass;
accessMode = lookupMode;
}
+ Lookup(Class> lookupClass, Class> prevLookupClass, int lookupMode) {
+ this(lookupClass, prevLookupClass, lookupMode, true);
+ }
+
+ Lookup(Class> lookupClass, int lookupMode, boolean doCheck) {
+ this(lookupClass, null, lookupMode, doCheck);
+ }
+
Lookup(Class> lookupClass, int lookupMode) {
- this(lookupClass, lookupMode, true);
+ this(lookupClass, lookupMode, true);
}
Lookup(Class> lookupClass) {
@@ -206,8 +221,8 @@ static final public class Lookup {
}
Lookup(Class> lookupClass, boolean performSecurityCheck) {
- this(lookupClass, FULL_ACCESS_MASK, performSecurityCheck);
- }
+ this(lookupClass, FULL_ACCESS_MASK, performSecurityCheck);
+ }
/**
* A query to determine the lookup capabilities held by this instance.
@@ -217,7 +232,6 @@ static final public class Lookup {
public int lookupModes() {
return accessMode;
}
-
/*
* Is the varargs bit set?
@@ -400,7 +414,7 @@ void checkAccess(Class> clazz) throws IllegalAccessException {
checkClassAccess(clazz);
}
/*[ENDIF]*/
-
+
/**
* Checks whether {@link #accessClass} can access a specific member of the {@code referenceClass}.
* Equivalent of visible.c checkVisibility();
@@ -430,10 +444,17 @@ private void checkAccess(Class> definingClass, Class> referenceClass, String
Module accessModule = accessClass.getModule();
try {
+ /*[IF Java14]*/
+ checkClassModuleVisibility(accessMode, accessClass, prevAccessClass, type.returnType);
+ for (Class> c: type.arguments) {
+ checkClassModuleVisibility(accessMode, accessClass, prevAccessClass, c);
+ }
+ /*[ELSE]*/
checkClassModuleVisibility(accessMode, accessModule, type.returnType);
for (Class> c: type.arguments) {
checkClassModuleVisibility(accessMode, accessModule, c);
}
+ /*[ENDIF] Java14*/
} catch (IllegalAccessException exc) {
IllegalAccessError err = new IllegalAccessError(exc.getMessage());
err.initCause(exc);
@@ -454,7 +475,19 @@ private void checkAccess(Class> definingClass, Class> referenceClass, String
}
} else if (Modifier.isProtected(memberModifiers)) {
/* Ensure that the accessMode is not restricted (public-only) */
- if (PUBLIC != accessMode) {
+ /*[IF !Java14]*/
+ if (accessMode != PUBLIC)
+ /*[ELSE]*/
+ /* Note: the lookup with the PUBLIC plus MODULE or UNCONDITIONAL mode
+ * can access public types in all modules, which means the access to
+ * non-public types should be rejected if the PUBLIC plus MODULE
+ * or UNCONDITIONAL mode is specified.
+ */
+ if ((accessMode != PUBLIC)
+ && (accessMode != (PUBLIC | MODULE))
+ && (accessMode != UNCONDITIONAL))
+ /*[ENDIF] Java14 */
+ {
if (definingClass.isArray()) {
/* The only methods array classes have are defined on Object and thus accessible */
return;
@@ -535,28 +568,67 @@ private void checkAccess(Class> definingClass, Class> referenceClass, String
*/
private void checkClassAccess(Class> targetClass) throws IllegalAccessException {
/*[IF Sidecar19-SE]*/
+ /*[IF Java14]*/
+ checkClassModuleVisibility(accessMode, accessClass, prevAccessClass, targetClass);
+ /*[ELSE]*/
checkClassModuleVisibility(accessMode, accessClass.getModule(), targetClass);
+ /*[ENDIF] Java14*/
/*[ENDIF]*/
+
if (NO_ACCESS != accessMode) {
- /* target class should always be accessible to the lookup class when they are the same class */
- if (accessClass == targetClass) {
- return;
- }
-
- int modifiers = targetClass.getModifiers();
-
/* A protected class (must be a member class) is compiled to a public class as
* the protected flag of this class doesn't exist on the VM level (there is no
* access flag in the binary form representing 'protected')
*/
- if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) {
- /* Already determined that we have more than "no access" (public access) */
+ int targetClassModifiers = targetClass.getModifiers();
+ final boolean targetClassIsPublic = (Modifier.isPublic(targetClassModifiers) || Modifier.isProtected(targetClassModifiers));
+
+ /*[IF Java14]*/
+ Module accessModule = accessClass.getModule();
+ Module targetModule = targetClass.getModule();
+ String targetClassPackageName = targetClass.getPackageName();
+
+ /* An UNCONDITIONAL lookup has access to public types in any unconditionally exported package */
+ if (((UNCONDITIONAL & accessMode) == UNCONDITIONAL)
+ && targetClassIsPublic
+ && targetModule.isExported(targetClassPackageName)
+ ) {
return;
- } else {
- if (((PACKAGE == (accessMode & PACKAGE)) || Modifier.isPrivate(accessMode)) && isSamePackage(accessClass, targetClass)) {
+ } else if ((targetModule != null) && (accessModule != null)
+ && (accessModule.equals(targetModule) || (!accessModule.isNamed() && !targetModule.isNamed()))
+ ) {
+ if (((PRIVATE & accessMode) == PRIVATE)
+ && ((targetClass == accessClass) || targetClass.isNestmateOf(accessClass))
+ ) {
+ return;
+ } else if (((PACKAGE & accessMode) == PACKAGE) && isSamePackage(targetClass, accessClass)) {
+ return;
+ } else if (((MODULE & accessMode) == MODULE) && targetClassIsPublic) {
+ return;
+ } else if (((PUBLIC & accessMode) == PUBLIC) && targetClassIsPublic
+ && (((prevAccessClass != null) && targetModule.isExported(targetClassPackageName, prevAccessClass.getModule()))
+ || targetModule.isExported(targetClassPackageName))
+ ) {
return;
}
+ } else if ((PUBLIC & accessMode) == PUBLIC) {
+ /*[ENDIF] Java14*/
+ /* target class should always be accessible to the lookup class when they are the same class */
+ if (accessClass == targetClass) {
+ return;
+ }
+
+ if (targetClassIsPublic) {
+ /* Already determined that we have more than "no access" (public access) */
+ return;
+ } else {
+ if (((PACKAGE == (accessMode & PACKAGE)) || Modifier.isPrivate(accessMode)) && isSamePackage(accessClass, targetClass)) {
+ return;
+ }
+ }
+ /*[IF Java14]*/
}
+ /*[ENDIF] Java14*/
}
/*[MSG "K0680", "Class '{0}' no access to: class '{1}'"]*/
@@ -769,6 +841,77 @@ private static String getModuleName(Module module) {
}
return moduleName;
}
+
+ /*[IF Java14]*/
+ /**
+ * Check if targetClass is in a package visible from the accessModule
+ * whether the previous lookup class is present or not
+ *
+ * @param accessMode access mode of the lookup object
+ * @param accessClass the referring class
+ * @param prevAccessClass the previous lookup class
+ * @param targetClass Class which the referring class is accessing
+ * @throws IllegalAccessException if the targetClass is not visible
+ */
+ static void checkClassModuleVisibility(int accessMode, Class> accessClass, Class> prevAccessClass, Class> targetClass) throws IllegalAccessException {
+ if (prevAccessClass == null) {
+ checkClassModuleVisibility(accessMode, accessClass.getModule(), targetClass);
+ }else {
+ checkClassModuleVisibilityWithPrevAccessClass(accessClass, prevAccessClass, targetClass);
+ }
+ }
+ /**
+ * Check if targetClass is in a package visible from the accessModule in the presense of the previous lookup class
+ *
+ * @param accessModule module of the referring class
+ * @param prevAccessClass the previous lookup class
+ * @param targetClass Class which the referring class is accessing
+ * @return true if the targetClass is visible; otherwise return false
+ */
+ static void checkClassModuleVisibilityWithPrevAccessClass(Class> accessClass, Class> prevAccessClass, Class> targetClass) throws IllegalAccessException {
+ Module prevAccessClassModule = prevAccessClass.getModule();
+ Module accessModule = accessClass.getModule();
+ Module targetModule = targetClass.getModule();
+ String targetClassPackageName = targetClass.getPackageName();
+
+ if ((prevAccessClassModule != null) && (accessModule != null) && (targetModule != null)) {
+ if (prevAccessClassModule.equals(targetModule)
+ || (!prevAccessClassModule.isNamed() && !targetModule.isNamed())
+ ) {
+ if (!accessModule.canRead(prevAccessClassModule)) {
+ /*[MSG "K0679", "Module '{0}' no access to: package '{1}' because module '{0}' can't read module '{2}'"]*/
+ throw throwIllegalAccessException(accessModule, prevAccessClassModule, prevAccessClass.getPackageName(), "K0679"); //$NON-NLS-1$
+ } else if (!targetModule.isExported(targetClassPackageName, accessModule)) {
+ /*[MSG "K0677", "Module '{0}' no access to: package '{1}' which is not exported by module '{2}' to module '{0}'"]*/
+ throw throwIllegalAccessException(accessModule, targetModule, targetClassPackageName, "K0677"); //$NON-NLS-1$
+ }
+ } else if (accessModule.equals(targetModule)
+ || (!accessModule.isNamed() && !targetModule.isNamed())
+ ) {
+ if (!prevAccessClassModule.canRead(accessModule)) {
+ /*[MSG "K0679", "Module '{0}' no access to: package '{1}' because module '{0}' can't read module '{2}'"]*/
+ throw throwIllegalAccessException(prevAccessClassModule, accessModule, accessClass.getPackageName(), "K0679"); //$NON-NLS-1$
+ } else if (!targetModule.isExported(targetClassPackageName, prevAccessClassModule)) {
+ /*[MSG "K0677", "Module '{0}' no access to: package '{1}' which is not exported by module '{2}' to module '{0}'"]*/
+ throw throwIllegalAccessException(prevAccessClassModule, targetModule, targetClassPackageName, "K0677"); //$NON-NLS-1$
+ }
+ } else if (!prevAccessClassModule.canRead(targetModule)) {
+ /*[MSG "K0679", "Module '{0}' no access to: package '{1}' because module '{0}' can't read module '{2}'"]*/
+ throw throwIllegalAccessException(prevAccessClassModule, targetModule, targetClassPackageName, "K0679"); //$NON-NLS-1$
+ } else if (!accessModule.canRead(targetModule)) {
+ /*[MSG "K0679", "Module '{0}' no access to: package '{1}' because module '{0}' can't read module '{2}'"]*/
+ throw throwIllegalAccessException(accessModule, targetModule, targetClassPackageName, "K0679"); //$NON-NLS-1$
+ } else if (!targetModule.isExported(targetClassPackageName, prevAccessClassModule)) {
+ /*[MSG "K0677", "Module '{0}' no access to: package '{1}' which is not exported by module '{2}' to module '{0}'"]*/
+ throw throwIllegalAccessException(prevAccessClassModule, targetModule, targetClassPackageName, "K0677"); //$NON-NLS-1$
+ } else if (!targetModule.isExported(targetClassPackageName, accessModule)) {
+ /*[MSG "K0677", "Module '{0}' no access to: package '{1}' which is not exported by module '{2}' to module '{0}'"]*/
+ throw throwIllegalAccessException(accessModule, targetModule, targetClassPackageName, "K0677"); //$NON-NLS-1$
+ }
+ }
+ }
+ /*[ENDIF] Java14*/
+
/**
* Check if targetClass is in a package visible from the accessModule
* @param accessMode access mode of the lookup object
@@ -776,7 +919,6 @@ private static String getModuleName(Module module) {
* @param targetClass Class which the referring class is accessing
* @throws IllegalAccessException if the targetClass is not visible
*/
-
static void checkClassModuleVisibility(int accessMode, Module accessModule, Class> targetClass) throws IllegalAccessException {
if (INTERNAL_PRIVILEGED != accessMode) {
Module targetModule = targetClass.getModule();
@@ -793,8 +935,10 @@ static void checkClassModuleVisibility(int accessMode, Module accessModule, Clas
} else if (!targetModule.isExported(targetClassPackageName)) {
// Need MODULE access to see packages conditionally exported
if (((MODULE & accessMode) != MODULE)
- || (!accessModule.equals(targetModule)
- && !targetModule.isExported(targetClassPackageName, accessModule))) {
+ || (!accessModule.equals(targetModule)
+ && (accessModule.isNamed() || targetModule.isNamed())
+ && !targetModule.isExported(targetClassPackageName, accessModule))
+ ) {
throw throwIllegalAccessException(accessModule, targetModule, targetClassPackageName, "K0677"); //$NON-NLS-1$
}
}
@@ -1100,29 +1244,52 @@ public MethodHandle findStaticSetter(Class> clazz, String fieldName, Class>
return handle;
}
+ /*[IF Java14]*/
/**
* Create a lookup on the request class. The resulting lookup will have no more
* access privileges than the original.
*
* @param lookupClass - the class to create the lookup on
* @return a new MethodHandles.Lookup object
+ * @throws NullPointerException - if lookupClass is null
+ * @throws IllegalArgumentException - if the requested Class is a primitive type or an array class
*/
- public MethodHandles.Lookup in(Class> lookupClass){
- lookupClass.getClass(); // implicit null check
+ public MethodHandles.Lookup in(Class> lookupClass) throws NullPointerException, IllegalArgumentException {
+ /*[ELSE]*/
+ /**
+ * Create a lookup on the request class. The resulting lookup will have no more
+ * access privileges than the original.
+ *
+ * @param lookupClass - the class to create the lookup on
+ * @return a new MethodHandles.Lookup object
+ */
+ public MethodHandles.Lookup in(Class> lookupClass) {
+ /*[ENDIF] Java14 */
+ Objects.requireNonNull(lookupClass);
+
+ /*[IF Java14]*/
+ if (lookupClass.isPrimitive() || lookupClass.isArray()) {
+ /*[MSG "K065T", "The requested class: {0} must not be a void type, primitive type or an array class"]*/
+ throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K065T", lookupClass.getCanonicalName())); //$NON-NLS-1$
+ }
+ /*[ENDIF] Java14 */
// If it's the same class as ourselves, return this
if (lookupClass == accessClass) {
return this;
}
+ int newAccessMode = accessMode;
/*[IF ]*/
/* If the new lookup class differs from the old one, protected members will not be accessible by virtue of inheritance. (Protected members may continue to be accessible because of package sharing.) */
/*[ENDIF]*/
/*[IF !Sidecar19-SE-OpenJ9]
- int newAccessMode = accessMode & ~PROTECTED;
+ newAccessMode &= ~PROTECTED;
/*[ELSE]*/
+ /*[IF !Java14]*/
/* The UNCONDITIONAL bit is discarded if the new lookup class differs from the old one in Java 9 */
- int newAccessMode = accessMode & ~UNCONDITIONAL;
+ newAccessMode &= ~UNCONDITIONAL;
+ /*[ENDIF] Java14 */
/* There are 3 cases to be addressed for the new lookup class from a different module:
* 1) There is no access if the package containing the new lookup class is not exported to
@@ -1137,7 +1304,9 @@ public MethodHandles.Lookup in(Class> lookupClass){
if (!Objects.equals(accessClassModule, lookupClassModule)) {
if (!lookupClassModule.isExported(lookupClass.getPackageName(), accessClassModule)) {
newAccessMode = NO_ACCESS;
- } else if (accessClassModule.isNamed()) {
+ } else
+ /*[IF !Java14]*/
+ if (accessClassModule.isNamed()) {
/* If the old lookup class is in a named module different from the new lookup class,
* we should keep the public access only when it is a public lookup.
*/
@@ -1146,7 +1315,9 @@ public MethodHandles.Lookup in(Class> lookupClass){
} else {
newAccessMode = NO_ACCESS;
}
- } else {
+ } else
+ /*[ENDIF] Java14 */
+ {
newAccessMode &= ~MODULE;
}
}
@@ -1173,16 +1344,13 @@ public MethodHandles.Lookup in(Class> lookupClass){
}
}
- /*[IF ]*/
- /* If the new lookup class is not accessible to the old lookup class, then no members, not even public members, will be accessible. (In all other cases, public members will continue to be accessible.) */
- /*[ENDIF]*/
- /* Treat a protected class as public as the access flag of a protected class
- * is set to public when compiled to a class file.
+ /* A protected class (must be a member class) is compiled to a public class as
+ * the protected flag of this class doesn't exist on the VM level (there is no
+ * access flag in the binary form representing 'protected')
*/
int lookupClassModifiers = lookupClass.getModifiers();
- if(!Modifier.isPublic(lookupClassModifiers)
- && !Modifier.isProtected(lookupClassModifiers)
- ){
+ final boolean lookupClassIsPublic = (Modifier.isPublic(lookupClassModifiers) || Modifier.isProtected(lookupClassModifiers));
+ if(!lookupClassIsPublic) {
if(isSamePackage(accessClass, lookupClass)) {
if (0 == (accessMode & PACKAGE)) {
newAccessMode = NO_ACCESS;
@@ -1197,7 +1365,60 @@ public MethodHandles.Lookup in(Class> lookupClass){
}
}
- return new Lookup(lookupClass, newAccessMode);
+ /*[IF Java14]*/
+ /* If the new lookup class is not accessible to the old lookup class,
+ * then no members, not even public members, will be accessible.
+ * Note: the invocation of accessClass() is explicitly required since JDK14
+ * to do the access check on the requested lookup class.
+ */
+ if (!isClassAccessible(lookupClass)) {
+ newAccessMode = NO_ACCESS;
+ }
+
+ /* There is no access for the requested lookup class if the previous lookup
+ * class's module is different from the modules of the requested lookup class
+ * and the old lookup class (i.e.teleporting to a third module).
+ * e.g.
+ * when the previous lookup class is in the module called M0,
+ * the old lookup class is in the module called M1 and the requested lookup
+ * class is in the module called M2, if M0 != M1 && M1 != M2 && M0 != M2
+ * (only one module among them is allowed to be unnamed), then teleporting
+ * from M0 to M2 (a 3rd module) will lose all accesses.
+ * Note: all unnamed modules are treated as the same modules.
+ */
+ Module prevAccessClassModule = (prevAccessClass != null) ? prevAccessClass.getModule() : null;
+ if (prevAccessClassModule != null) {
+ boolean isDiffModule1 = (!Objects.equals(prevAccessClassModule, accessClassModule)
+ && (prevAccessClassModule.isNamed() || accessClassModule.isNamed()));
+ boolean isDiffModule2 = (!Objects.equals(accessClassModule, lookupClassModule)
+ && (accessClassModule.isNamed() || lookupClassModule.isNamed()));
+ boolean isDiffModule3 = (!Objects.equals(prevAccessClassModule, lookupClassModule)
+ && (prevAccessClassModule.isNamed() || lookupClassModule.isNamed()));
+
+ if (isDiffModule1 && isDiffModule2 && isDiffModule3) {
+ newAccessMode = NO_ACCESS;
+ }
+ }
+
+ /* Set up the previous lookup class as the new previous lookup class assuming
+ * the requested & currently configured lookup classes are in the same module;
+ * otherwise, the new previous lookup class is the old lookup class.
+ */
+ Class> newPrevAccessClass = (Objects.equals(lookupClassModule, accessClassModule)) ?
+ prevAccessClass : accessClass;
+
+ /* If the existing access mode has UNCONDITIONAL bit, which means the previous
+ * lookup class of the old lookup is also null, then there is no previous lookup
+ * class for the requested lookup class.
+ */
+ if ((accessMode & UNCONDITIONAL) == UNCONDITIONAL) {
+ newPrevAccessClass = null;
+ }
+
+ return new Lookup(lookupClass, newPrevAccessClass, newAccessMode);
+ /*[ELSE]*/
+ return new Lookup(lookupClass, newAccessMode);
+ /*[ENDIF] Java14*/
}
/*
@@ -1223,6 +1444,32 @@ public Class> lookupClass() {
return accessClass;
}
+ /*[IF Java14]*/
+ /**
+ * The class previously being used for visibility checks and access permissions.
+ *
+ * @return The class previously used in by this Lookup object for access checking
+ */
+ public Class> previousLookupClass() {
+ return prevAccessClass;
+ }
+
+ /**
+ * Check whether the target class is accessible to the lookup class.
+ *
+ * @param targetClass The {@link Class} being accessed.
+ * @return true if the accessiblity check is passed; otherwise return false.
+ */
+ private boolean isClassAccessible(Class> targetClass) {
+ try {
+ accessClass(targetClass);
+ } catch (IllegalAccessException exc) {
+ return false;
+ }
+ return true;
+ }
+ /*[ENDIF] Java14*/
+
/**
* Make a MethodHandle to the Reflect method. If the method is non-static, the receiver argument
* is treated as the initial argument in the MethodType.
@@ -1552,6 +1799,12 @@ public MethodHandleInfo revealDirect(MethodHandle target) throws IllegalArgument
@Override
public String toString() {
String toString = accessClass.getName();
+ /*[IF Java14]*/
+ if (prevAccessClass != null) {
+ toString += "/" + prevAccessClass.getName(); //$NON-NLS-1$
+ }
+ /*[ENDIF] Java14*/
+
switch(accessMode) {
case NO_ACCESS:
toString += "/noaccess"; //$NON-NLS-1$
@@ -1560,6 +1813,22 @@ public String toString() {
toString += "/public"; //$NON-NLS-1$
break;
/*[IF Sidecar19-SE-OpenJ9]
+ /*[IF Java14]*/
+ case UNCONDITIONAL:
+ toString += "/publicLookup"; //$NON-NLS-1$
+ break;
+ case PUBLIC | MODULE:
+ toString += "/module"; //$NON-NLS-1$
+ break;
+ case PUBLIC | PACKAGE: /* fall through */
+ case PUBLIC | PACKAGE | MODULE:
+ toString += "/package"; //$NON-NLS-1$
+ break;
+ case PUBLIC | PACKAGE | PRIVATE: /* fall through */
+ case PUBLIC | PACKAGE | PRIVATE | MODULE:
+ toString += "/private"; //$NON-NLS-1$
+ break;
+ /*[ELSE]*/
case PUBLIC | UNCONDITIONAL:
toString += "/publicLookup"; //$NON-NLS-1$
break;
@@ -1572,6 +1841,7 @@ public String toString() {
case PUBLIC | PACKAGE | PRIVATE | MODULE:
toString += "/private"; //$NON-NLS-1$
break;
+ /*[ENDIF] Java14 */
/*[ELSE]*/
case PUBLIC | PACKAGE:
toString += "/package"; //$NON-NLS-1$
@@ -1855,8 +2125,9 @@ public Class> defineClass(byte[] classBytes) throws NullPointerException, Ille
/**
* Return a MethodHandles.Lookup object without the requested lookup mode.
+ * Note: the requested mode must exists in the access mode; otherwise, do nothing.
*
- * @param dropMode the mode to be dropped
+ * @param dropMode the mode to be dropped which must exists in the access mode
* @return a MethodHandles.Lookup object without the requested lookup mode
* @throws IllegalArgumentException - if the requested lookup mode is not one of the existing access modes
*/
@@ -1865,32 +2136,73 @@ public MethodHandles.Lookup dropLookupMode(int dropMode) {
* as it is not set up for lookup objects by default.
*/
int fullAccessMode = FULL_ACCESS_MASK | MODULE | UNCONDITIONAL;
+
+ switch(dropMode) {
+ case PUBLIC:
+ case MODULE:
+ case PACKAGE:
+ case PRIVATE:
+ case PROTECTED:
+ case UNCONDITIONAL:
+ /* dropMode is OK */
+ break;
+ default:
+ /*[MSG "K065R", "The requested lookup mode: 0x{0} is not one of the existing access modes: 0x{1}"]*/
+ throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K065R", Integer.toHexString(dropMode), Integer.toHexString(fullAccessMode))); //$NON-NLS-1$
+ }
+ /*[IF Java14]*/
+ /* The lookup object has to discard the protected access by default */
+ int newAccessMode = accessMode & ~PROTECTED;
+ /*[ELSE]*/
/* The lookup object has to discard the protected and unconditional access by default */
int newAccessMode = accessMode & ~(PROTECTED | UNCONDITIONAL);
+ /*[ENDIF] Java14*/
- switch (dropMode) {
+ /* The access mode to be dropped must exist in the current access mode;
+ * otherwise, the new access mode remains unchanged.
+ */
+ switch (dropMode & newAccessMode) {
case PUBLIC:
newAccessMode = NO_ACCESS;
break;
- case MODULE:
- newAccessMode &= ~(MODULE | PACKAGE | PRIVATE);
- break;
case PACKAGE:
newAccessMode &= ~(PACKAGE | PRIVATE);
break;
case PRIVATE:
newAccessMode &= ~PRIVATE;
break;
- case PROTECTED:
case UNCONDITIONAL:
+ /*[IF Java14]*/
+ newAccessMode = NO_ACCESS;
+ /*[ENDIF] Java14*/
break;
default:
- /*[MSG "K065R", "The requested lookup mode: 0x{0} is not one of the existing access modes: 0x{1}"]*/
- throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K065R", Integer.toHexString(dropMode), Integer.toHexString(fullAccessMode))); //$NON-NLS-1$
+ /* no change in the access mode */
+ }
+
+ /* The exception is MODULE in which case all access bits involved must be dropped
+ * whether or not the MODULE bit exists in the access mode.
+ */
+ if ((dropMode == MODULE) || ((dropMode & newAccessMode) == MODULE)) {
+ newAccessMode &= ~(MODULE | PACKAGE | PRIVATE);
+ }
+
+ /*[IF Java14]*/
+ /* There is no previous lookup class for the requested lookup class
+ * if the MODULE or UNCONDITIONAL bit is set in the new access mode.
+ */
+ Class> newPrevAccessClass = prevAccessClass;
+ if (((newAccessMode & MODULE) == MODULE)
+ || ((newAccessMode & UNCONDITIONAL) == UNCONDITIONAL)
+ ) {
+ newPrevAccessClass = null;
}
- return new Lookup(accessClass, newAccessMode);
+ return new Lookup(accessClass, newPrevAccessClass, newAccessMode);
+ /*[ELSE]*/
+ return new Lookup(accessClass, newAccessMode);
+ /*[ENDIF] Java14*/
}
/**
@@ -1898,14 +2210,35 @@ public MethodHandles.Lookup dropLookupMode(int dropMode) {
*
* @return a boolean type indicating whether the lookup class has private access
*/
+ @Deprecated(forRemoval=false, since="14")
public boolean hasPrivateAccess() {
/* Full access for use by MH implementation */
if (INTERNAL_PRIVILEGED == accessMode) {
return true;
}
+ /*[IF Java14]*/
+ return (!isWeakenedLookup() && (MODULE == (accessMode & MODULE)));
+ /*[ELSE]*/
return !isWeakenedLookup();
+ /*[ENDIF] Java14*/
+ }
+
+ /*[IF Java14]*/
+ /**
+ * Return true if the lookup class has full privilege access
+ *
+ * @return a boolean type indicating whether the lookup class has full privilege access
+ */
+ public boolean hasFullPrivilegeAccess() {
+ /* Full access for use by MH implementation */
+ if (INTERNAL_PRIVILEGED == accessMode) {
+ return true;
+ }
+
+ return (!isWeakenedLookup() && (MODULE == (accessMode & MODULE)));
}
+ /*[ENDIF] Java14*/
/*[ENDIF]*/
}
@@ -1960,7 +2293,7 @@ public static MethodHandles.Lookup privateLookupIn(Class> targetClass, MethodH
}
if (targetClass.isPrimitive() || targetClass.isArray()) {
- /*[MSG "K065T", "The target class: {0} must not be a primitive type or an array class"]*/
+ /*[MSG "K065T", "The requested class: {0} must not be a void type, primitive type or an array class"]*/
throw new IllegalArgumentException(com.ibm.oti.util.Msg.getString("K065T", targetClass.getCanonicalName())); //$NON-NLS-1$
}
@@ -1985,17 +2318,32 @@ public static MethodHandles.Lookup privateLookupIn(Class> targetClass, MethodH
}
int callerLookupMode = callerLookup.lookupModes();
+ /*[IF Java14]*/
+ if (!callerLookup.hasFullPrivilegeAccess()) {
+ /*[MSG "K065W1", "The access mode: 0x{0} of the caller lookup doesn't have the PRIVATE & MODULE mode : 0x{1}"]*/
+ throw new IllegalAccessException(com.ibm.oti.util.Msg.getString("K065W1", Integer.toHexString(callerLookupMode), Integer.toHexString(Lookup.PRIVATE | Lookup.MODULE))); //$NON-NLS-1$
+ }
+ /*[ELSE]*/
if (Lookup.MODULE != (Lookup.MODULE & callerLookupMode)) {
- /*[MSG "K065W", "The access mode: 0x{0} of the caller lookup doesn't have the MODULE mode : 0x{1}"]*/
- throw new IllegalAccessException(com.ibm.oti.util.Msg.getString("K065W", Integer.toHexString(callerLookupMode), Integer.toHexString(Lookup.MODULE))); //$NON-NLS-1$
+ /*[MSG "K065W2", "The access mode: 0x{0} of the caller lookup doesn't have the MODULE mode : 0x{1}"]*/
+ throw new IllegalAccessException(com.ibm.oti.util.Msg.getString("K065W2", Integer.toHexString(callerLookupMode), Integer.toHexString(Lookup.MODULE))); //$NON-NLS-1$
}
+ /*[ENDIF] Java14*/
SecurityManager secmgr = System.getSecurityManager();
if (null != secmgr) {
secmgr.checkPermission(com.ibm.oti.util.ReflectPermissions.permissionSuppressAccessChecks);
}
+ /*[IF Java14]*/
+ if (Objects.equals(targetClassModule, accessClassModule)) {
+ return new Lookup(targetClass, null, callerLookupMode);
+ } else {
+ return new Lookup(targetClass, callerLookup.lookupClass(), (callerLookupMode & ~Lookup.MODULE));
+ }
+ /*[ELSE]*/
return new Lookup(targetClass);
+ /*[ENDIF] Java14*/
}
/*[ENDIF] Sidecar19-SE-OpenJ9*/
diff --git a/test/functional/Jsr292/playlist.xml b/test/functional/Jsr292/playlist.xml
index 50efbc5a8a0..bbaa5f06175 100644
--- a/test/functional/Jsr292/playlist.xml
+++ b/test/functional/Jsr292/playlist.xml
@@ -1,7 +1,7 @@
+
+ jsr292Test_Lookup
+
+ NoOptions
+ Mode195
+
+ $(JAVA_COMMAND) $(JVM_OPTIONS) \
+ --add-opens=java.base/java.lang=ALL-UNNAMED \
+ -Djava.security.policy=$(Q)$(TEST_RESROOT)$(D)java.policy$(Q) \
+ -cp $(Q)$(TEST_RESROOT)$(D)jsr292test.jar$(P)$(RESOURCES_DIR)$(P)$(TESTNG)$(P)$(LIB_DIR)$(D)asm-all.jar$(Q) \
+ org.testng.TestNG -d $(REPORTDIR) $(Q)$(TEST_RESROOT)$(D)testng.xml$(Q) \
+ -testnames jsr292Test_Lookup \
+ -groups $(TEST_GROUP) \
+ -excludegroups $(DEFAULT_EXCLUDE); \
+ $(TEST_STATUS)
+
+ extended
+
+
+ functional
+
+
+ 9
+ 10
+ 11
+ 13
+
+
+ openj9
+ ibm
+
+
+
+
+ jsr292Test_Lookup_JitCount0
+
+ -Xjit:count=0
+
+ $(JAVA_COMMAND) $(JVM_OPTIONS) \
+ --add-opens=java.base/java.lang=ALL-UNNAMED \
+ -Djava.security.policy=$(Q)$(TEST_RESROOT)$(D)java.policy$(Q) \
+ -cp $(Q)$(TEST_RESROOT)$(D)jsr292test.jar$(P)$(RESOURCES_DIR)$(P)$(TESTNG)$(P)$(LIB_DIR)$(D)asm-all.jar$(Q) \
+ org.testng.TestNG -d $(REPORTDIR) $(Q)$(TEST_RESROOT)$(D)testng.xml$(Q) \
+ -testnames jsr292Test_Lookup \
+ -groups $(TEST_GROUP) \
+ -excludegroups $(DEFAULT_EXCLUDE); \
+ $(TEST_STATUS)
+ ^arch.arm
+
+ extended
+
+
+ functional
+
+
+ 9
+ 10
+ 11
+ 13
+
+
+ openj9
+ ibm
+
+
diff --git a/test/functional/Jsr292/testng.xml b/test/functional/Jsr292/testng.xml
index 502f1094b04..3dcd1e9a4bb 100644
--- a/test/functional/Jsr292/testng.xml
+++ b/test/functional/Jsr292/testng.xml
@@ -1,7 +1,7 @@
+
+
openj9_jsr292Test
$(JAVA_COMMAND) $(JVM_OPTIONS) \
@@ -41,7 +49,8 @@
functional
- 9+
+ 11
+ 13
@@ -67,7 +76,8 @@
functional
- 9+
+ 11
+ 13
openj9