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
261 /**
262 * The access flag {@code ACC_TRANSIENT}, corresponding to the
263 * source modifier {@link Modifier#TRANSIENT transient}, with a
264 * mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>.
265 */
266 TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, null),
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
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 }
|
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 access flag {@code ACC_IDENTITY}, corresponding to the
193 * source modifier {@link Modifier#IDENTITY identity}, with a mask
194 * value of <code>{@value "0x%04x" Modifier#IDENTITY}</code>.
195 * @jvms 4.1 -B. Class access and property modifiers
196 */
197 IDENTITY(Modifier.IDENTITY, true, Location.SET_CLASS_INNER_CLASS, null),
198
199 /**
200 * The module flag {@code ACC_OPEN} with a mask value of {@code
201 * 0x0020}.
202 * @see java.lang.module.ModuleDescriptor#isOpen
203 */
204 OPEN(0x0000_0020, false, Location.SET_MODULE,
205 new Function<ClassFileFormatVersion, Set<Location>>() {
206 @Override
207 public Set<Location> apply(ClassFileFormatVersion cffv) {
208 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
209 Location.SET_MODULE:
210 Location.EMPTY_SET;}
211 }),
212
213 /**
214 * The module requires flag {@code ACC_TRANSITIVE} with a mask
215 * value of {@code 0x0020}.
216 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
217 */
218 TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
219 new Function<ClassFileFormatVersion, Set<Location>>() {
220 @Override
221 public Set<Location> apply(ClassFileFormatVersion cffv) {
222 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
223 Location.SET_MODULE_REQUIRES:
224 Location.EMPTY_SET;}
225 }),
226
227 /**
228 * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
229 * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with
230 * a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
231 */
232 SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null),
233
234 /**
235 * The module requires flag {@code ACC_STATIC_PHASE} with a mask
236 * value of {@code 0x0040}.
237 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
238 */
239 STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES,
240 new Function<ClassFileFormatVersion, Set<Location>>() {
241 @Override
242 public Set<Location> apply(ClassFileFormatVersion cffv) {
243 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
244 Location.SET_MODULE_REQUIRES:
245 Location.EMPTY_SET;}
246 }),
247
248 /**
249 * The access flag {@code ACC_VALUE}, corresponding to the
250 * source modifier {@link Modifier#VALUE value}, with a mask
251 * value of <code>{@value "0x%04x" Modifier#VALUE}</code>.
252 * @jvms 4.1 -B. Class access and property modifiers
253 */
254 VALUE(Modifier.VALUE, true, Set.of(Location.CLASS, Location.INNER_CLASS), null),
255
256 /**
257 * The access flag {@code ACC_VOLATILE}, corresponding to the
258 * source modifier {@link Modifier#VOLATILE volatile}, with a mask
259 * value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
260 */
261 VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null),
262 /**
263 * The access flag {@code ACC_BRIDGE} with a mask value of
264 * <code>{@value "0x%04x" Modifier#BRIDGE}</code>
265 * @see Method#isBridge()
266 */
267 BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD,
268 new Function<ClassFileFormatVersion, Set<Location>>() {
269 @Override
270 public Set<Location> apply(ClassFileFormatVersion cffv) {
271 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
272 Location.SET_METHOD:
273 Location.EMPTY_SET;}
274 }),
275
276 /**
277 * The access flag {@code ACC_TRANSIENT}, corresponding to the
278 * source modifier {@link Modifier#TRANSIENT transient}, with a
279 * mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>.
280 */
281 TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, null),
488 public Set<Location> locations(ClassFileFormatVersion cffv) {
489 Objects.requireNonNull(cffv);
490 if (cffvToLocations == null) {
491 return locations;
492 } else {
493 return cffvToLocations.apply(cffv);
494 }
495 }
496
497 /**
498 * {@return an unmodifiable set of access flags for the given mask value
499 * appropriate for the location in question}
500 *
501 * @param mask bit mask of access flags
502 * @param location context to interpret mask value
503 * @throws IllegalArgumentException if the mask contains bit
504 * positions not support for the location in question
505 */
506 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
507 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class);
508 int unmatchedFlags = mask;
509 for (var accessFlag : LocationToFlags.locationToFlags.get(location)) {
510 int accessMask = accessFlag.mask();
511 if ((mask & accessMask) != 0) {
512 result.add(accessFlag);
513 unmatchedFlags = unmatchedFlags & ~accessMask;
514 }
515 }
516 if (unmatchedFlags != 0) {
517 throw new IllegalArgumentException("Unmatched bit position 0x" +
518 Integer.toHexString(unmatchedFlags) +
519 " for location " + location);
520 }
521 return Collections.unmodifiableSet(result);
522 }
523
524 /**
525 * A location within a class file where flags can be applied.
526 *
527 * Note that since these locations represent class file structures
528 * rather than language structures many language structures, such
529 * as constructors and interfaces, are <em>not</em> present.
530 * @since 20
531 */
532 public enum Location {
533 /**
534 * Class location.
535 * @jvms 4.1 The ClassFile Structure
536 */
537 CLASS,
538
622 Set.of(CLASS, FIELD, METHOD,
623 INNER_CLASS, METHOD_PARAMETER);
624 private static final Set<Location> SET_SYNTHETIC_9 =
625 // Added as an access flag in 7
626 Set.of(CLASS, FIELD, METHOD,
627 INNER_CLASS,
628 METHOD_PARAMETER, // Added in 8
629 // Module-related items added in 9
630 MODULE, MODULE_REQUIRES,
631 MODULE_EXPORTS, MODULE_OPENS);
632 private static final Set<Location> SET_MANDATED_9 =
633 Set.of(METHOD_PARAMETER, // From 8
634 // Starting in 9
635 MODULE, MODULE_REQUIRES,
636 MODULE_EXPORTS, MODULE_OPENS);
637 }
638
639 private static class LocationToFlags {
640 private static Map<Location, Set<AccessFlag>> locationToFlags =
641 Map.ofEntries(entry(Location.CLASS,
642 Set.of(PUBLIC, FINAL, SUPER, IDENTITY, VALUE,
643 INTERFACE, ABSTRACT,
644 SYNTHETIC, ANNOTATION,
645 ENUM, AccessFlag.MODULE)),
646 entry(Location.FIELD,
647 Set.of(PUBLIC, PRIVATE, PROTECTED,
648 STATIC, FINAL, VOLATILE,
649 TRANSIENT, SYNTHETIC, ENUM)),
650 entry(Location.METHOD,
651 Set.of(PUBLIC, PRIVATE, PROTECTED,
652 STATIC, FINAL, SYNCHRONIZED,
653 BRIDGE, VARARGS, NATIVE,
654 ABSTRACT, STRICT, SYNTHETIC)),
655 entry(Location.INNER_CLASS,
656 Set.of(PUBLIC, PRIVATE, PROTECTED, IDENTITY, VALUE,
657 STATIC, FINAL, INTERFACE, ABSTRACT,
658 SYNTHETIC, ANNOTATION, ENUM)),
659 entry(Location.METHOD_PARAMETER,
660 Set.of(FINAL, SYNTHETIC, MANDATED)),
661 entry(Location.MODULE,
662 Set.of(OPEN, SYNTHETIC, MANDATED)),
663 entry(Location.MODULE_REQUIRES,
664 Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)),
665 entry(Location.MODULE_EXPORTS,
666 Set.of(SYNTHETIC, MANDATED)),
667 entry(Location.MODULE_OPENS,
668 Set.of(SYNTHETIC, MANDATED)));
669 }
670 }
|