8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.reflect;
27
28 import java.util.Collections;
29 import java.util.Objects;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.function.Function;
33 import static java.util.Map.entry;
34
35 /**
36 * Represents a JVM access or module-related flag on a runtime member,
37 * such as a {@linkplain Class class}, {@linkplain Field field}, or
38 * {@linkplain Executable method}.
39 *
40 * <P>JVM access and module-related flags are related to, but distinct
41 * from Java language {@linkplain Modifier modifiers}. Some modifiers
42 * and access flags have a one-to-one correspondence, such as {@code
43 * public}. In other cases, some language-level modifiers do
44 * <em>not</em> have an access flag, such as {@code sealed} (JVMS
45 * {@jvms 4.7.31}) and some access flags have no corresponding
46 * modifier, such as {@linkplain #SYNTHETIC synthetic}.
47 *
168 new Function<ClassFileFormatVersion, Set<Location>>() {
169 @Override
170 public Set<Location> apply(ClassFileFormatVersion cffv) {
171 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_8) >= 0) {
172 return Location.SET_FINAL_8;
173 } else {
174 return (cffv == ClassFileFormatVersion.RELEASE_0) ?
175 Location.SET_CLASS_FIELD_METHOD :
176 Location.SET_CLASS_FIELD_METHOD_INNER_CLASS;
177 }
178 }
179 }),
180
181 /**
182 * The access flag {@code ACC_SUPER} with a mask value of {@code
183 * 0x0020}.
184 *
185 * @apiNote
186 * In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
187 * flag as set in every class file (JVMS {@jvms 4.1}).
188 */
189 SUPER(0x0000_0020, false, Location.SET_CLASS, null),
190
191 /**
192 * The module flag {@code ACC_OPEN} with a mask value of {@code
193 * 0x0020}.
194 * @see java.lang.module.ModuleDescriptor#isOpen
195 */
196 OPEN(0x0000_0020, false, Location.SET_MODULE,
197 new Function<ClassFileFormatVersion, Set<Location>>() {
198 @Override
199 public Set<Location> apply(ClassFileFormatVersion cffv) {
200 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
201 Location.SET_MODULE:
202 Location.EMPTY_SET;}
203 }),
204
205 /**
206 * The module requires flag {@code ACC_TRANSITIVE} with a mask
207 * value of {@code 0x0020}.
208 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
209 */
210 TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
211 new Function<ClassFileFormatVersion, Set<Location>>() {
212 @Override
213 public Set<Location> apply(ClassFileFormatVersion cffv) {
214 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
215 Location.SET_MODULE_REQUIRES:
216 Location.EMPTY_SET;}
217 }),
218
219 /**
220 * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
221 * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with
222 * a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
223 */
224 SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null),
225
226 /**
227 * The module requires flag {@code ACC_STATIC_PHASE} with a mask
228 * value of {@code 0x0040}.
229 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
230 */
231 STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES,
232 new Function<ClassFileFormatVersion, Set<Location>>() {
233 @Override
234 public Set<Location> apply(ClassFileFormatVersion cffv) {
235 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
236 Location.SET_MODULE_REQUIRES:
237 Location.EMPTY_SET;}
238 }),
239
240 /**
241 * The access flag {@code ACC_VOLATILE}, corresponding to the
242 * source modifier {@link Modifier#VOLATILE volatile}, with a mask
243 * value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
244 */
245 VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null),
246
247 /**
248 * The access flag {@code ACC_BRIDGE} with a mask value of
249 * <code>{@value "0x%04x" Modifier#BRIDGE}</code>
250 * @see Method#isBridge()
251 */
252 BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD,
253 new Function<ClassFileFormatVersion, Set<Location>>() {
254 @Override
255 public Set<Location> apply(ClassFileFormatVersion cffv) {
256 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
257 Location.SET_METHOD:
258 Location.EMPTY_SET;}
259 }),
260
469 * given class file format version}
470 * @param cffv the class file format version to use
471 * @throws NullPointerException if the parameter is {@code null}
472 */
473 public Set<Location> locations(ClassFileFormatVersion cffv) {
474 Objects.requireNonNull(cffv);
475 if (cffvToLocations == null) {
476 return locations;
477 } else {
478 return cffvToLocations.apply(cffv);
479 }
480 }
481
482 /**
483 * {@return an unmodifiable set of access flags for the given mask value
484 * appropriate for the location in question}
485 *
486 * @param mask bit mask of access flags
487 * @param location context to interpret mask value
488 * @throws IllegalArgumentException if the mask contains bit
489 * positions not support for the location in question
490 */
491 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
492 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class);
493 for (var accessFlag : LocationToFlags.locationToFlags.get(location)) {
494 int accessMask = accessFlag.mask();
495 if ((mask & accessMask) != 0) {
496 result.add(accessFlag);
497 mask = mask & ~accessMask;
498 }
499 }
500 if (mask != 0) {
501 throw new IllegalArgumentException("Unmatched bit position 0x" +
502 Integer.toHexString(mask) +
503 " for location " + location);
504 }
505 return Collections.unmodifiableSet(result);
506 }
507
508 /**
509 * A location within a class file where flags can be applied.
510 *
511 * Note that since these locations represent class file structures
512 * rather than language structures many language structures, such
513 * as constructors and interfaces, are <em>not</em> present.
514 * @since 20
515 */
516 public enum Location {
517 /**
518 * Class location.
519 * @jvms 4.1 The ClassFile Structure
520 */
521 CLASS,
522
523 /**
524 * Field location.
525 * @jvms 4.5 Fields
526 */
527 FIELD,
606 Set.of(CLASS, FIELD, METHOD,
607 INNER_CLASS, METHOD_PARAMETER);
608 private static final Set<Location> SET_SYNTHETIC_9 =
609 // Added as an access flag in 7
610 Set.of(CLASS, FIELD, METHOD,
611 INNER_CLASS,
612 METHOD_PARAMETER, // Added in 8
613 // Module-related items added in 9
614 MODULE, MODULE_REQUIRES,
615 MODULE_EXPORTS, MODULE_OPENS);
616 private static final Set<Location> SET_MANDATED_9 =
617 Set.of(METHOD_PARAMETER, // From 8
618 // Starting in 9
619 MODULE, MODULE_REQUIRES,
620 MODULE_EXPORTS, MODULE_OPENS);
621 }
622
623 private static class LocationToFlags {
624 private static Map<Location, Set<AccessFlag>> locationToFlags =
625 Map.ofEntries(entry(Location.CLASS,
626 Set.of(PUBLIC, FINAL, SUPER,
627 INTERFACE, ABSTRACT,
628 SYNTHETIC, ANNOTATION,
629 ENUM, AccessFlag.MODULE)),
630 entry(Location.FIELD,
631 Set.of(PUBLIC, PRIVATE, PROTECTED,
632 STATIC, FINAL, VOLATILE,
633 TRANSIENT, SYNTHETIC, ENUM)),
634 entry(Location.METHOD,
635 Set.of(PUBLIC, PRIVATE, PROTECTED,
636 STATIC, FINAL, SYNCHRONIZED,
637 BRIDGE, VARARGS, NATIVE,
638 ABSTRACT, STRICT, SYNTHETIC)),
639 entry(Location.INNER_CLASS,
640 Set.of(PUBLIC, PRIVATE, PROTECTED,
641 STATIC, FINAL, INTERFACE, ABSTRACT,
642 SYNTHETIC, ANNOTATION, ENUM)),
643 entry(Location.METHOD_PARAMETER,
644 Set.of(FINAL, SYNTHETIC, MANDATED)),
645 entry(Location.MODULE,
646 Set.of(OPEN, SYNTHETIC, MANDATED)),
647 entry(Location.MODULE_REQUIRES,
648 Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)),
649 entry(Location.MODULE_EXPORTS,
650 Set.of(SYNTHETIC, MANDATED)),
651 entry(Location.MODULE_OPENS,
652 Set.of(SYNTHETIC, MANDATED)));
653 }
654 }
|
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.reflect;
27
28 import jdk.internal.javac.PreviewFeature;
29 import jdk.internal.misc.PreviewFeatures;
30
31 import java.util.Collections;
32 import java.util.Objects;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.function.Function;
36 import static java.util.Map.entry;
37
38 /**
39 * Represents a JVM access or module-related flag on a runtime member,
40 * such as a {@linkplain Class class}, {@linkplain Field field}, or
41 * {@linkplain Executable method}.
42 *
43 * <P>JVM access and module-related flags are related to, but distinct
44 * from Java language {@linkplain Modifier modifiers}. Some modifiers
45 * and access flags have a one-to-one correspondence, such as {@code
46 * public}. In other cases, some language-level modifiers do
47 * <em>not</em> have an access flag, such as {@code sealed} (JVMS
48 * {@jvms 4.7.31}) and some access flags have no corresponding
49 * modifier, such as {@linkplain #SYNTHETIC synthetic}.
50 *
171 new Function<ClassFileFormatVersion, Set<Location>>() {
172 @Override
173 public Set<Location> apply(ClassFileFormatVersion cffv) {
174 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_8) >= 0) {
175 return Location.SET_FINAL_8;
176 } else {
177 return (cffv == ClassFileFormatVersion.RELEASE_0) ?
178 Location.SET_CLASS_FIELD_METHOD :
179 Location.SET_CLASS_FIELD_METHOD_INNER_CLASS;
180 }
181 }
182 }),
183
184 /**
185 * The access flag {@code ACC_SUPER} with a mask value of {@code
186 * 0x0020}.
187 *
188 * @apiNote
189 * In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
190 * flag as set in every class file (JVMS {@jvms 4.1}).
191 * If preview feature is enabled,
192 * the {@code 0x0020} access flag bit is {@linkplain #IDENTITY IDENTITY access flag}.
193 */
194 SUPER(0x0000_0020, false,
195 PreviewFeatures.isEnabled() ? Location.EMPTY_SET : Location.SET_CLASS,
196 new Function<ClassFileFormatVersion, Set<Location>>() {
197 @Override
198 public Set<Location> apply(ClassFileFormatVersion cffv) {
199 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_22) >= 0) &&
200 PreviewFeatures.isEnabled() ? Location.EMPTY_SET : Location.SET_CLASS;
201 }
202 }),
203
204 /**
205 * The access flag {@code ACC_IDENTITY}, corresponding to the
206 * source modifier {@link Modifier#IDENTITY identity}, with a mask
207 * value of <code>{@value "0x%04x" Modifier#IDENTITY}</code>.
208 * @jvms 4.1 -B. Class access and property modifiers
209 */
210 @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS)
211 IDENTITY(Modifier.IDENTITY, false,
212 PreviewFeatures.isEnabled() ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET,
213 new Function<ClassFileFormatVersion, Set<Location>>() {
214 @Override
215 public Set<Location> apply(ClassFileFormatVersion cffv) {
216 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_22) >= 0
217 && PreviewFeatures.isEnabled())
218 ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET;
219 }
220 }),
221
222 /**
223 * The module flag {@code ACC_OPEN} with a mask value of {@code
224 * 0x0020}.
225 * @see java.lang.module.ModuleDescriptor#isOpen
226 */
227 OPEN(0x0000_0020, false, Location.SET_MODULE,
228 new Function<ClassFileFormatVersion, Set<Location>>() {
229 @Override
230 public Set<Location> apply(ClassFileFormatVersion cffv) {
231 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
232 Location.SET_MODULE:
233 Location.EMPTY_SET;}
234 }),
235
236 /**
237 * The module requires flag {@code ACC_TRANSITIVE} with a mask
238 * value of {@code 0x0020}.
239 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
240 */
241 TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
242 new Function<ClassFileFormatVersion, Set<Location>>() {
243 @Override
244 public Set<Location> apply(ClassFileFormatVersion cffv) {
245 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
246 Location.SET_MODULE_REQUIRES:
247 Location.EMPTY_SET;}
248 }),
249
250 /**
251 * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
252 * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with
253 * a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
254 */
255 SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null),
256
257 /**
258 * The module requires flag {@code ACC_STATIC_PHASE} with a mask
259 * value of {@code 0x0040}.
260 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
261 */
262 STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES,
263 new Function<ClassFileFormatVersion, Set<Location>>() {
264 @Override
265 public Set<Location> apply(ClassFileFormatVersion cffv) {
266 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
267 Location.SET_MODULE_REQUIRES:
268 Location.EMPTY_SET;}
269 }),
270
271 /**
272 * The access flag {@code ACC_VOLATILE}, corresponding to the
273 * source modifier {@link Modifier#VOLATILE volatile}, with a mask
274 * value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
275 */
276 VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null),
277
278 /**
279 * The access flag {@code ACC_BRIDGE} with a mask value of
280 * <code>{@value "0x%04x" Modifier#BRIDGE}</code>
281 * @see Method#isBridge()
282 */
283 BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD,
284 new Function<ClassFileFormatVersion, Set<Location>>() {
285 @Override
286 public Set<Location> apply(ClassFileFormatVersion cffv) {
287 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
288 Location.SET_METHOD:
289 Location.EMPTY_SET;}
290 }),
291
500 * given class file format version}
501 * @param cffv the class file format version to use
502 * @throws NullPointerException if the parameter is {@code null}
503 */
504 public Set<Location> locations(ClassFileFormatVersion cffv) {
505 Objects.requireNonNull(cffv);
506 if (cffvToLocations == null) {
507 return locations;
508 } else {
509 return cffvToLocations.apply(cffv);
510 }
511 }
512
513 /**
514 * {@return an unmodifiable set of access flags for the given mask value
515 * appropriate for the location in question}
516 *
517 * @param mask bit mask of access flags
518 * @param location context to interpret mask value
519 * @throws IllegalArgumentException if the mask contains bit
520 * positions not supported for the location in question
521 */
522 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
523 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class);
524 for (var accessFlag : LocationToFlags.locationToFlags.get(location)) {
525 int accessMask = accessFlag.mask();
526 if ((mask & accessMask) != 0) {
527 result.add(accessFlag);
528 mask = mask & ~accessMask;
529 if (mask == 0) {
530 break; // no more mask bits
531 }
532 }
533 }
534 if (mask != 0) {
535 throw new IllegalArgumentException("Unmatched bit position 0x" +
536 Integer.toHexString(mask) +
537 " for location " + location);
538 }
539 return Collections.unmodifiableSet(result);
540 }
541
542 /**
543 * {@return an unmodifiable set of access flags for the given mask value
544 * appropriate for the location in question}
545 *
546 * @param mask bit mask of access flags
547 * @param location context to interpret mask value
548 * @param cffv the class file format version
549 * @throws IllegalArgumentException if the mask contains bit
550 * positions not supported for the location in question
551 */
552 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location,
553 ClassFileFormatVersion cffv) {
554 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class);
555 for (var accessFlag : AccessFlag.values()) {
556 int accessMask = accessFlag.mask();
557 if ((mask & accessMask) != 0) {
558 var locations = accessFlag.locations(cffv);
559 if (locations.contains(location)) {
560 result.add(accessFlag);
561 mask = mask & ~accessMask;
562 if (mask == 0) {
563 break; // no more mask bits
564 }
565 }
566 }
567 }
568 if (mask != 0) {
569 throw new IllegalArgumentException("Unmatched bit position 0x" +
570 Integer.toHexString(mask) +
571 " for location " + location +
572 " for class file format version " + cffv);
573 }
574 return Collections.unmodifiableSet(result);
575 }
576
577
578 /**
579 * A location within a class file where flags can be applied.
580 *
581 * Note that since these locations represent class file structures
582 * rather than language structures many language structures, such
583 * as constructors and interfaces, are <em>not</em> present.
584 * @since 20
585 */
586 public enum Location {
587 /**
588 * Class location.
589 * @jvms 4.1 The ClassFile Structure
590 */
591 CLASS,
592
593 /**
594 * Field location.
595 * @jvms 4.5 Fields
596 */
597 FIELD,
676 Set.of(CLASS, FIELD, METHOD,
677 INNER_CLASS, METHOD_PARAMETER);
678 private static final Set<Location> SET_SYNTHETIC_9 =
679 // Added as an access flag in 7
680 Set.of(CLASS, FIELD, METHOD,
681 INNER_CLASS,
682 METHOD_PARAMETER, // Added in 8
683 // Module-related items added in 9
684 MODULE, MODULE_REQUIRES,
685 MODULE_EXPORTS, MODULE_OPENS);
686 private static final Set<Location> SET_MANDATED_9 =
687 Set.of(METHOD_PARAMETER, // From 8
688 // Starting in 9
689 MODULE, MODULE_REQUIRES,
690 MODULE_EXPORTS, MODULE_OPENS);
691 }
692
693 private static class LocationToFlags {
694 private static Map<Location, Set<AccessFlag>> locationToFlags =
695 Map.ofEntries(entry(Location.CLASS,
696 Set.of(PUBLIC, FINAL, (PreviewFeatures.isEnabled() ? IDENTITY : SUPER),
697 INTERFACE, ABSTRACT,
698 SYNTHETIC, ANNOTATION,
699 ENUM, AccessFlag.MODULE)),
700 entry(Location.FIELD,
701 Set.of(PUBLIC, PRIVATE, PROTECTED,
702 STATIC, FINAL, VOLATILE,
703 TRANSIENT, SYNTHETIC, ENUM, STRICT)),
704 entry(Location.METHOD,
705 Set.of(PUBLIC, PRIVATE, PROTECTED,
706 STATIC, FINAL, SYNCHRONIZED,
707 BRIDGE, VARARGS, NATIVE,
708 ABSTRACT, STRICT, SYNTHETIC)),
709 entry(Location.INNER_CLASS,
710 Set.of(PUBLIC, PRIVATE, PROTECTED, IDENTITY,
711 STATIC, FINAL, INTERFACE, ABSTRACT,
712 SYNTHETIC, ANNOTATION, ENUM)),
713 entry(Location.METHOD_PARAMETER,
714 Set.of(FINAL, SYNTHETIC, MANDATED)),
715 entry(Location.MODULE,
716 Set.of(OPEN, SYNTHETIC, MANDATED)),
717 entry(Location.MODULE_REQUIRES,
718 Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)),
719 entry(Location.MODULE_EXPORTS,
720 Set.of(SYNTHETIC, MANDATED)),
721 entry(Location.MODULE_OPENS,
722 Set.of(SYNTHETIC, MANDATED)));
723 }
724 }
|