Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8281463: [lworld] VALUE / PRIMITIVE modifiers should be supported by reflection #698

Closed
wants to merge 30 commits into from
Closed
Changes from 2 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
96578de
8281463: [lworld] VALUE / PRIMITIVE modifiers should be supported by …
RogerRiggs May 25, 2022
f28fb08
Add Class.isIdentity
RogerRiggs May 24, 2022
f83c35f
Restore AccessFlag SUPER
RogerRiggs May 27, 2022
482e3f4
Re-enable StaticFactoryTest
RogerRiggs May 31, 2022
33e24a0
Update handling of obsolete ACC_SUPER and remove ACC_PERMITSVALUE
RogerRiggs Jun 1, 2022
c7883a6
Add Class.is(AccessFlag) to test for a single flag.
RogerRiggs May 27, 2022
cd8d0de
Merge branch 'lworld' into 8287250-class-identity
RogerRiggs Jun 7, 2022
946eea0
Merge branch 'lworld' into 8281463-value-modifiers
RogerRiggs Jun 7, 2022
9af6875
Address review comments
RogerRiggs Jun 7, 2022
cab6cae
Revert changes and simplify
RogerRiggs Jun 7, 2022
349a939
Replace static int constants with AccessFlag method calls.
RogerRiggs Jun 8, 2022
f089c22
Merge branch 'lworld' into 8287250-class-identity
RogerRiggs Jun 16, 2022
d6dbe8f
Proxy class definition needs ACC_IDENTITY
RogerRiggs Jun 15, 2022
558d873
Merge branch 'lworld' into 8281463-value-modifiers
RogerRiggs Jun 17, 2022
605d386
Sync with jdk AccessFlag updates.
RogerRiggs Jun 24, 2022
8f37b14
Merge branch 'lworld' into 8281463-value-modifiers
RogerRiggs Jul 28, 2022
a220770
Merge branch 'lworld' into 8287250-class-identity
RogerRiggs Jul 28, 2022
b3a7ea7
Cleanup of modifier use
RogerRiggs Aug 2, 2022
dcd5d44
Merge branch '8287250-class-identity' into 8281463-value-modifiers
RogerRiggs Aug 2, 2022
ea58a93
Resync with mainline AccessFlag changes
RogerRiggs Aug 2, 2022
754c41c
Restore some tests and cleanup
RogerRiggs Aug 2, 2022
dd10bd4
Revert additions of ACC_PRIMITIVE to Modifier and AccessFlags.
RogerRiggs Aug 3, 2022
ecd28d1
Merge branch 'lworld' into 8281463-value-modifiers
RogerRiggs Aug 26, 2022
efdb333
Match up AccessFlag and Modifier
RogerRiggs Aug 26, 2022
9b2c0f0
Merge branch 'lworld' into 8281463-value-modifiers
RogerRiggs Sep 1, 2022
b7343b5
Merge branch 'lworld' into 8281463-value-modifiers
RogerRiggs Sep 2, 2022
28ef42f
Updated defneHiddenClass/BasicTest for EmptyHiddenAbstractClass
RogerRiggs Sep 2, 2022
e25b124
Merge branch 'lworld' into 8281463-value-modifiers
RogerRiggs Sep 6, 2022
d3c5b54
Update javadoc to resolve review comments.
RogerRiggs Sep 6, 2022
9a21fe0
Correct jvms references for identity and value modifiers
RogerRiggs Sep 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/java.base/share/classes/java/lang/Class.java
Original file line number Diff line number Diff line change
@@ -204,7 +204,6 @@ public final class Class<T> implements java.io.Serializable,
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;
private static final int VALUE_CLASS = 0x00000040;
private static final int PERMITS_VALUE = 0x00000100;
private static final int PRIMITIVE_CLASS = 0x00000800;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VALUE_CLASS and PRIMITIVE_CLASS can be removed now and replaced with AccessFlag::mask.


private static native void registerNatives();
@@ -511,8 +510,8 @@ private static Class<?> forName(String name, boolean initialize, ClassLoader loa

/** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;


@@ -1505,6 +1504,14 @@ public Set<AccessFlag> accessFlags() {
AccessFlag.Location.CLASS);
}

/**
* {@return true if this class has the requested {@link AccessFlag}}
* @param flag an {@link AccessFlag}
*/
public boolean is(AccessFlag flag) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this API needed? We can do Class.accessFlags().contains(flag). This discussion should belong to PR 7445 (see my comment in the Modifier).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are significant performance concerns. The current implementation of getModifers() is an intrinsic and all of the tests for modifiers are boolean operations against static constants.
Doing a Set.contains against a set that is re-built every time getAccessFlags() is called is a non-starter.
Many of the access flags have dedicated methods in j.l.Class, for example, isPublic, isStatic, etc.
It would improve usability and performance to be able to check for an accessFlag in a simple direct operation.
I'll keep this for the time being.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new API requires discussion and also whether it needs to be performant. Can you bring this discussion to PR 7445.

Class::isValue, Class::isIdentity and Class::isPrimitive is performance-sensitive and the current implementation is performant checking against the modifiers. Is there a case that Class::isXXX cannot be used?

return (getModifiers() & flag.mask()) == flag.mask();
}

/**
* If this {@code Class} object represents a local or anonymous
* class within a method, returns a {@link
22 changes: 8 additions & 14 deletions src/java.base/share/classes/java/lang/reflect/AccessFlag.java
Original file line number Diff line number Diff line change
@@ -131,14 +131,12 @@ public enum AccessFlag {
* ACC_SUPER or the class file version number, and the flag no longer had any effect.
* Now the flag has been repurposed as ACC_IDENTITY.
*/
SUPER(0x0000_0020, false, Set.of(Location.CLASS)),
// SUPER(0x0000_0020, false, Set.of(Location.CLASS)),

/**
* The access flag {@code ACC_IDENTITY} corresponding to the
* source modifier {@link Modifier#VALUE value} with a mask
* value of {@code 0x0020}.
* The access flag {@code ACC_IDENTITY} with a mask value of {@code 0x0020}.
*/
IDENTITY(Modifier.IDENTITY, true, Set.of(Location.CLASS)),
IDENTITY(0x0000_0020, false, Set.of(Location.CLASS)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can also be in Location.INNER_CLASS. Same for value and primitive.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


/**
* The module flag {@code ACC_OPEN} with a mask value of {@code
@@ -169,11 +167,9 @@ public enum AccessFlag {
STATIC_PHASE(0x0000_0040, false, Set.of(Location.MODULE_REQUIRES)),

/**
* The access flag {@code ACC_VALUE} corresponding to the
* source modifier {@link Modifier#VALUE value} with a mask
* value of {@code 0x0040}.
* The access flag {@code ACC_VALUE} with a mask value of {@code 0x0040}.
*/
VALUE(Modifier.VALUE, true, Set.of(Location.CLASS)),
VALUE(0x0000_0040, false, Set.of(Location.CLASS)),

/**
* The access flag {@code ACC_VOLATILE}, corresponding to the
@@ -227,11 +223,9 @@ public enum AccessFlag {
Set.of(Location.CLASS, Location.METHOD, Location.INNER_CLASS)),

/**
* The access flag {@code ACC_PRIMITIVE}, corresponding to the source
* modifier {@link Modifier#PRIMITIVE primitive} with a mask
* value of {@code 0x0800}.
* The access flag {@code ACC_PRIMITIVE} with a mask value of {@code 0x0800}.
*/
PRIMITIVE(Modifier.PRIMITIVE, true, Set.of(Location.CLASS)),
PRIMITIVE(0x0000_0800, false, Set.of(Location.CLASS)),

/**
* The access flag {@code ACC_STRICT}, corresponding to the source
@@ -431,7 +425,7 @@ private static class LocationToFlags {
BRIDGE, VARARGS, NATIVE,
ABSTRACT, STRICT, SYNTHETIC)),
entry(Location.INNER_CLASS,
Set.of(PUBLIC, PRIVATE, PROTECTED,
Set.of(PUBLIC, PRIVATE, PROTECTED, IDENTITY, VALUE, PRIMITIVE,
STATIC, FINAL, INTERFACE, ABSTRACT,
SYNTHETIC, ANNOTATION, ENUM)),
entry(Location.METHOD_PARAMETER,
26 changes: 0 additions & 26 deletions src/java.base/share/classes/java/lang/reflect/Modifier.java
Original file line number Diff line number Diff line change
@@ -232,9 +232,6 @@ public static boolean isStrict(int mod) {
* {@code toString} with the appropriate mask from a method like
* {@link #constructorModifiers} or {@link #methodModifiers}.
*
* @apiNote TBD: This method does not reflect the class related modifiers including
* {@link #IDENTITY}, {@link #VALUE}, and {@link #PRIMITIVE}.
*
* @param mod a set of modifiers
* @return a string representation of the set of modifiers
* represented by {@code mod}
@@ -300,27 +297,13 @@ public static String toString(int mod) {
*/
public static final int FINAL = 0x00000010;

/**
* The {@code int} value representing the {@code ACC_IDENTITY}
* modifier when applied to the modifiers of a class.
* @see AccessFlag#IDENTITY
*/
public static final int IDENTITY = 0x00000020;

/**
* The {@code int} value representing the {@code synchronized}
* modifier.
* @see AccessFlag#SYNCHRONIZED
*/
public static final int SYNCHRONIZED = 0x00000020;

/**
* The {@code int} value representing the {@code ACC_VALUE}
* modifier when applied to the modifiers of a class.
* @see AccessFlag#VALUE
*/
public static final int VALUE = 0x00000040;

/**
* The {@code int} value representing the {@code volatile}
* modifier.
@@ -362,13 +345,6 @@ public static String toString(int mod) {
*/
public static final int STRICT = 0x00000800;

/**
* The {@code int} value representing the {@code ACC_PRIMITIVE}
* modifier when applied to the modifiers of a class.
* @see AccessFlag#PRIMITIVE
*/
public static final int PRIMITIVE = 0x00000800;

// Bits not (yet) exposed in the public API either because they
// have different meanings for fields and methods and there is no
// way to distinguish between the two in this class, or because
@@ -403,7 +379,6 @@ static boolean isMandated(int mod) {
*/
private static final int CLASS_MODIFIERS =
Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE |
Modifier.IDENTITY | Modifier.VALUE | Modifier.PRIMITIVE |
Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL |
Modifier.STRICT;

@@ -413,7 +388,6 @@ static boolean isMandated(int mod) {
*/
private static final int INTERFACE_MODIFIERS =
Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE |
Modifier.IDENTITY | Modifier.VALUE |
Modifier.ABSTRACT | Modifier.STATIC | Modifier.STRICT;


Original file line number Diff line number Diff line change
@@ -58,6 +58,7 @@
*/
package jdk.internal.org.objectweb.asm;

import java.lang.reflect.AccessFlag;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -682,8 +683,7 @@ private static void appendDescriptor(final Class<?> clazz, final StringBuilder s
}

static boolean isPrimitiveClass(Class<?> clazz) {
int mods = clazz.getModifiers();
return (mods & 0x00000100) != 0;
return clazz.is(AccessFlag.PRIMITIVE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return clazz.is(AccessFlag.PRIMITIVE);
return clazz.accessFlags().contains(AccessFlag.PRIMITIVE);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not performant.

}

// -----------------------------------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -29,7 +29,8 @@
* @run main/othervm InnerClassAttributeValuenessTest
*/

import com.sun.tools.classfile.AccessFlags;
import java.lang.reflect.AccessFlag;
import java.util.Set;

public class InnerClassAttributeValuenessTest {

@@ -48,7 +49,12 @@ public static Inner create(int v) {
}

public static void main(String[] args) {
if ((Inner.class.getModifiers() & AccessFlags.ACC_PRIMITIVE) == 0)
Set<AccessFlag> flags = Inner.class.accessFlags();
System.out.println("accessFlags: " + flags);

if (!Inner.class.is(AccessFlag.VALUE))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!Inner.class.is(AccessFlag.VALUE))
if (!flags.contains(AccessFlag.VALUE))

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not performant.

throw new AssertionError("Value flag missing");
if (!Inner.class.is(AccessFlag.PRIMITIVE))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!Inner.class.is(AccessFlag.PRIMITIVE))
if (!flags.contains(AccessFlag.PRIMITIVE))

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

throw new AssertionError("Primitive Value flag missing");
}
}