JDK-8251375 : Mark methods that not present in source with ACC_MANDATED in bytecode
  • Type: Enhancement
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 16
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2020-08-11
  • Updated: 2021-05-07
Related Reports
Relates :  
Relates :  
Description
Sometimes java compiler emits methods that not present in source code but mandated by specification. Examples are: default constructor; enum methods like value() and valueOf(); record methods like equals(), hashCode(), toString() (when not specified explicitly). These methods are not marked in class files, so from the class-file alone, it could be hard to say whether the method was actually present in the source.

There are bytecode tools that can benefit from knowing whether the method was not present in the source. This includes decompilers like Fernflower, code coverage agent like JaCoCo, mutation coverage tools like pitest.

Sometimes it's possible to apply heuristics. E.g. if the record equals method contains invokedynamic instruction with bootstrap method java.lang.runtime.ObjectMethods::bootstrap then it's likely not present in the source. It's harder for other methods like default constructor or implicit canonical constructor in records. If debug information is available, the tool can try to guess from LineNumberTable attribute whether the given method was present in the source but this is still unreliable.

Internally, javac tracks the Elements.Origin.MANDATED value for mandated members. Some program elements already have ACC_MANDATED (0x8000) flag in the flags field. This includes parameters (JVMS 4.7.24), modules, requires, exports and opens (JVMS 4.7.25). It looks quite natural to allow ACC_MANDATED in method access_flags as well and update the compiler to emit it when applicable. The corresponding bit (0x8000) in access_flags structure is not used currently (JVMS 4.6).

This change would require minor updates of JVM specification and Java Language Specification. Namely:
1. In JVM specification add the following row to the "Table 4.6-A. Method access and property flags":
ACC_MANDATED | 0x8000 | Declared method not present in the source code but required by the language specification

2. In JVM specification add the following paragraph to section "4.6. Methods" after the 'The ACC_SYNTHETIC flag' paragraph:
The ACC_MANDATED flag indicates that the method was implicitly declared in source code, according to the specification of the language in which the source code was written (JLS ��13.1). (The method is mandated by a language specification, so all compilers for the language must emit it.)

3. In Java language specification update the list item 12 in the section "13.1 The Form of a Binary" like this:
A construct emitted by a Java compiler must be marked as mandated if it corresponds to a formal parameter or a method declared implicitly in source code (��8.8.1, ��8.8.9, ��8.9.3, ��15.9.5.1).
The following formal parameters are declared implicitly in source code:
- The first formal parameter of a constructor of a non-private inner member class (��8.8.1, ��8.8.9).
- The first formal parameter of an anonymous constructor of an anonymous class whose superclass is inner or local (not in a static context) (��15.9.5.1).
- The formal parameter name of the valueOf method which is implicitly declared in an enum type (��8.9.3).
The following methods are declared implicitly in source code:
- Default constructors of classes and enum types (��8.8.9, ��8.9.2)
- Anonymous constructors (��15.9.5.1)
- The values and valueOf methods of enum types (��8.9.3)
- Certain public methods of interfaces (��9.2)
(more items should be added here for record preview feature)

For reference, the following constructs are declared implicitly in source code, but are not marked as mandated because only formal parameters and methods can be so marked in a class file (JVMS ��4.7.24):
- Certain public fields of enum types (��8.9.3)
- Container annotations (��9.7.5)