JDK-8298300 : Filtering AccessFlags by class file format version (i.e. ACC_SYNTHETIC)
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 20
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2022-12-07
  • Updated: 2025-02-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Description
The VM provides per class access flags such as ACC_SYNTHETIC for use by reflection APIs. The JVMS describes access flags and the class file format version(s) for which they are defined.

Is it expected that the flags provided to reflection are only those appropriate for the class file format version?
In one case, for a class file with version 49, 0x1000 access flag is present though it is not defined as ACC_SYNTHETIC until class file format version 50.
Comments
The current implementation of `accessFlags()` for fields and executables is built on `getModifiers()`. And `getModifiers() ` reports the VM's view of the class. Which merges the Synthetic attribute with the synthetic access flag from the classfile. That matches 2) semantics and will be inaccurate for 1) classfile bits when classfile version is < 50.
04-02-2025

There are at least two distinct flavor of questions modifies and access flags can be used to answer: 1) What bits were set of this structure in the class file? 2) Conceptually, what semantic attributes does this structure have? Most of the methods in core reflection should operate on flavor 2) (Class.isFoo(), Executable.isSynthetic(), etc.), but there is some utility to allowing 1) to be answered as well via the AccessFlags.
04-02-2025

This question arose with the introduction of java.lang.reflect.AccessFlag in JDK 20 and in particular the `maskToAccessFlags(mask, cffv)` method that interprets mask bits for a particular class file format version. The most useful behavior of that API would be report it for any element that did not appear in the source regardless of whether from the attribute or the access flag bit. It would be correctly indicating how the VM is treating the class/method/field. Not withstanding the JVMs specs, we could document the quirk related to the versions. If an application really needed the raw access flags from the class file, it could be recommended to use a class file API for that purpose. I would not suggest changing java.lang.reflect.Modifier or related.
31-01-2025

Thanks for writing this up David. To further complicate things, the modifiers are not the same as access flags for classes. To set modifiers, we filter out some access flags. So the java.lang.Class query looks at the modifiers, which from the JavaDoc getModifiers() should not return this bit. /** *{@return {@code true} if and only if this class has the synthetic modifier * bit set} * * @jls 13.1 The Form of a Binary * @jvms 4.1 The {@code ClassFile} Structure * @see <a * href="{@docRoot}/java.base/java/lang/reflect/package-summary.html#LanguageJvmModel">Java * programming language and JVM modeling in core reflection</a> * @since 1.5 */ public boolean isSynthetic() { return (getModifiers() & SYNTHETIC) != 0; } But yes, the VM treats both the Synthetic attribute and ACC_SYNTHETIC flag by setting the ACC_SYNTHETIC bit in the AccessFlags that are also present in the filtered Modifier flags. The JVMTI calls and reflection use AccessFlags which include ACC_SYNTHETIC for classfile versions < 50. Also, it appears that the JCK tests set the ACC_SYNTHETIC flag in classfile version 45 classfiles to test the JVMTI function isSyntheticMethod/Field rather than using the Synthetic attribute. The test can be fixed BUT is there classfile version 45 code *out there* that expect us to recognize the ACC_SYNTHETIC bit, since it's always been used this way.
31-01-2025

I needed to dig up a bit more history on the bit and the attribute ... So the Synthetic attribute was defined first for Java 1.1, classfile version 45.0 (JVMS 2nd Edition original IIUC). (I note there were some issues with its broad specification as there are now exemptions for certain compiler-generated methods.) The ACC_SYNTHETIC bit was introduced in Java 5, classfile version 49 - JSR 202. At that time javac switched from using the attribute to using the bit - JDK-4884882. The JVMS updated the synthetic attribute to state: > A class member that does not appear in the source code must be marked using a Synthetic > attribute, or else it must have its ACC_SYNTHETIC bit set. The only exceptions to this > requirement are for default constructors and the class initialization method. We also introduced Class.isSynthetic to report if the ACC_SYNTHETIC bit were set. It is very clear on this so I suspect it was a deliberate choice to not have it pay any attention to the synthetic attribute ... or it was a complete oversight because things "just worked" due to hotspot's implementation. Now looking at hotspot it seems that the synthetic attribute was always indicated by a bit in the "access flags" and ACC_SYNTHETIC is just the exposure of that bit to the world. So whether we set the bit because the VM saw a synthetic attribute, or because javac already set it directly in the classfile, we have no way to know (without going back to the classfile). So it really depends on what the higher-level API's are requiring here. If we truly only want to report on the ACC_SYNTHETIC bit then we should mask it out for classfile versions < Java 5. If we are really asking "is it synthetic" then we wouldn't mask it out.
31-01-2025

Per the jvms 4.7.8, the SYNTHETIC attribute and the ACC_SYNTHETIC access flag have the same semantics, as a marker on classfile elements that do not appear in the source. Hotspot sets ACC_SYNTHETIC when the SYNTHETIC attribute is encountered regardless of the class file format version. Strictly speaking ACC_SYNTHETIC should not be set for class file format versions < 50. However, it is convenient to have a consistent view of SYNTHETIC elements. [~darcy] It would be accurate and convenient for AccessFlag.SYNTHETIC to report the presence of the SYNTHETIC attribute for class files as far back as 45.3. Please review and comment.
30-01-2025

Any bit that is unused in that classfile version should be set to zero by the VM i.e. filtered out.
30-01-2025

The only use of synthetic in the jvm is for a JVMTI call IsSyntheticField and IsSyntheticMethod. We could filter out ACC_SYNTHETIC in the AccessFlags in classfile version < 50 and add a special non-access flag for pre-classfile version 50. And test both in JVMTI call. Maybe the VM should clear these access flags in pre-50 classfile versions for classfiles, methods and fields.
29-01-2025

I think the Java code in Class.java should do this. It can filter it out here, like: private int getClassAccessFlagsRaw() { Class<?> c = isArray() ? elementType() : this; int flags = c.getClassAccessFlagsRaw0(); return (getClassFileVersion() < 50) ? flags xor ACC_SYNTHETIC : flags; } These native functions: getClassAccessFlagsRaw0 and isArray() and getClassFileVersion0 are intrinsified by the JVM, so the code might not be that bad. Although moving all of these to Java-only code would be better.
29-01-2025

So now I've read about the Synthetic attribute in the JVMS 4.7.8. > The Synthetic attribute was introduced in JDK 1.1 to support nested classes and interfaces. Apparently now javac (and other bytecode generators ?) sets the ACC_SYNTHETIC AccessFlag rather than using this attribute, which is why I couldn't find it anywhere in any classfiles. Had to write my own. The conflation of these two things (attribute and access flag) is that the JVM has always set the ACC_SYNTHETIC access flag which it had defined internally before the JDK defined this flag, so the access flags are the only place where we store and use the value of ACC_SYNTHETIC for stuff. So recently, I've noticed that there are native methods in Class that call the JVM for final values that the JVM could easily just make fields in the Class. getClassFileVersion, getClassAccessFlags, isInterface, getModifiers, isArray. The JVM has intrinsics to make these natives faster than a native call but they could just be Java bytecodes. If getClassFileVersion and getClassAccess were all-Java, you could filter out ACC_SYNTHETIC in getAccessFlagsRaw directly for Class. Otherwise, I have to change all the C1/C2 intrinsics. Yuck. The JVM would still have to filter out ACC_SYNTHETIC for reflection for method and field for < classfile version 50. I linked an issue where I've done the same thing with getModifiers. JDK-8346567
29-01-2025

I cannot find an example of a class with a synthetic attribute anywhere. I can find ACC_SYNTHETIC set in access flags for classes, fields and methods but not the synthetic attribute. So for classes, this can be filtered out by the vm. Should ACC_SYNTHETIC access flag be filtered out for fields and methods too?
28-01-2025

The JVMS states: "All bits of the access_flags item not assigned in Table 4.1-B are reserved for future use. They should be set to zero in generated class files and should be ignored by Java Virtual Machine implementations." So if you load a classfile version where ACC_SYNTHETIC is set but it didn't exist then we should just ignore it - which to me means that it is filtered out.
20-01-2025

So the intension is that getClassAccessFlagsRaw() should not return ACC_SYNTHETIC for classfile version < 50? We could filter that out when saving the access flags in the class's AccessFlags. Does this also apply to fields and method access flags? Should we give an error if ACC_SYNTHETIC is used while parsing the class file or just filter it out? Or give an error if the synthetic attribute is used? (or would that be impossible for a classfile compiled with version < 50)?
17-01-2025