1 /*
  2  * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  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  *
 51  * <p>The values for the constants representing the access and module
 52  * flags are taken from sections of <cite>The Java Virtual Machine
 53  * Specification</cite> including {@jvms 4.1} (class access and
 54  * property modifiers), {@jvms 4.5} (field access and property flags),
 55  * {@jvms 4.6} (method access and property flags), {@jvms 4.7.6}
 56  * (nested class access and property flags), {@jvms 4.7.24} (method
 57  * parameters), and {@jvms 4.7.25} (module flags and requires,
 58  * exports, and opens flags).
 59  *
 60  * <p>The {@linkplain #mask() mask} values for the different access
 61  * flags are <em>not</em> distinct. Flags are defined for different
 62  * kinds of JVM structures and the same bit position has different
 63  * meanings in different contexts. For example, {@code 0x0000_0040}
 64  * indicates a {@link #VOLATILE volatile} field but a {@linkplain
 65  * #BRIDGE bridge method}; {@code 0x0000_0080} indicates a {@link
 66  * #TRANSIENT transient} field but a {@linkplain #VARARGS variable
 67  * arity (varargs)} method.
 68  *
 69  * @implSpec
 70  * The access flag constants are ordered by non-decreasing mask
 71  * value; that is the mask value of a constant is greater than or
 72  * equal to the mask value of an immediate neighbor to its (syntactic)
 73  * left. If new constants are added, this property will be
 74  * maintained. That implies new constants will not necessarily be
 75  * added at the end of the existing list.
 76  *
 77  * @apiNote
 78  * The JVM class file format has a {@linkplain ClassFileFormatVersion new version} defined for each new
 79  * {@linkplain Runtime.Version#feature() feature release}. A new class
 80  * file version may define new access flags or retire old ones. {@code
 81  * AccessFlag} is intended to model the set of access flags across
 82  * class file format versions. The range of versions an access flag is
 83  * recognized is not explicitly indicated in this API. See the current
 84  * <cite>The Java Virtual Machine Specification</cite> for
 85  * details. Unless otherwise indicated, access flags can be assumed to
 86  * be recognized in the {@linkplain Runtime#version() current
 87  * version}.
 88  *
 89  * @see java.lang.reflect.Modifier
 90  * @see java.lang.module.ModuleDescriptor.Modifier
 91  * @see java.lang.module.ModuleDescriptor.Requires.Modifier
 92  * @see java.lang.module.ModuleDescriptor.Exports.Modifier
 93  * @see java.lang.module.ModuleDescriptor.Opens.Modifier
 94  * @see java.compiler/javax.lang.model.element.Modifier
 95  * @since 20
 96  */
 97 @SuppressWarnings("doclint:reference") // cross-module link
 98 public enum AccessFlag {
 99     // Note to maintainers: anonymous class instances are used rather
100     // than lambdas to initialize the functions used for the
101     // cffvToLocations field to avoid using lambdas too early in JDK
102     // initialization.
103 
104     /**
105      * The access flag {@code ACC_PUBLIC}, corresponding to the source
106      * modifier {@link Modifier#PUBLIC public}, with a mask value of
107      * <code>{@value "0x%04x" Modifier#PUBLIC}</code>.
108      */
109     PUBLIC(Modifier.PUBLIC, true,
110            Location.SET_PUBLIC_1,
111            new Function<ClassFileFormatVersion, Set<Location>>() {
112                @Override
113                public Set<Location> apply(ClassFileFormatVersion cffv) {
114                    return (cffv == ClassFileFormatVersion.RELEASE_0) ?
115                        Location.SET_CLASS_FIELD_METHOD:
116                        Location.SET_PUBLIC_1;
117                }
118            }),
119 
120     /**
121      * The access flag {@code ACC_PRIVATE}, corresponding to the
122      * source modifier {@link Modifier#PRIVATE private}, with a mask
123      * value of <code>{@value "0x%04x" Modifier#PRIVATE}</code>.
124      */
125     PRIVATE(Modifier.PRIVATE, true, Location.SET_FIELD_METHOD_INNER_CLASS,
126             new Function<ClassFileFormatVersion, Set<Location>>() {
127                 @Override
128                     public Set<Location> apply(ClassFileFormatVersion cffv) {
129                     return (cffv == ClassFileFormatVersion.RELEASE_0) ?
130                         Location.SET_FIELD_METHOD:
131                         Location.SET_FIELD_METHOD_INNER_CLASS;
132                 }
133             }),
134 
135     /**
136      * The access flag {@code ACC_PROTECTED}, corresponding to the
137      * source modifier {@link Modifier#PROTECTED protected}, with a mask
138      * value of <code>{@value "0x%04x" Modifier#PROTECTED}</code>.
139      */
140     PROTECTED(Modifier.PROTECTED, true, Location.SET_FIELD_METHOD_INNER_CLASS,
141               new Function<ClassFileFormatVersion, Set<Location>>() {
142                   @Override
143                   public Set<Location> apply(ClassFileFormatVersion cffv) {
144                   return (cffv == ClassFileFormatVersion.RELEASE_0) ?
145                       Location.SET_FIELD_METHOD:
146                       Location.SET_FIELD_METHOD_INNER_CLASS;
147                   }
148               }),
149 
150     /**
151      * The access flag {@code ACC_STATIC}, corresponding to the source
152      * modifier {@link Modifier#STATIC static}, with a mask value of
153      * <code>{@value "0x%04x" Modifier#STATIC}</code>.
154      */
155     STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS,
156            new Function<ClassFileFormatVersion, Set<Location>>() {
157                @Override
158                public Set<Location> apply(ClassFileFormatVersion cffv) {
159                    return (cffv == ClassFileFormatVersion.RELEASE_0) ?
160                        Location.SET_FIELD_METHOD:
161                        Location.SET_FIELD_METHOD_INNER_CLASS;}
162            }),
163 
164     /**
165      * The access flag {@code ACC_FINAL}, corresponding to the source
166      * modifier {@link Modifier#FINAL final}, with a mask
167      * value of <code>{@value "0x%04x" Modifier#FINAL}</code>.
168      */
169     FINAL(Modifier.FINAL, true,
170           Location.SET_FINAL_8,
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.latest()) >= 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      * 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      * @since Valhalla
211      */
212     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS, reflective=true)
213     IDENTITY(Modifier.IDENTITY, false,
214             PreviewFeatures.isEnabled() ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET,
215             new Function<ClassFileFormatVersion, Set<Location>>() {
216                 @Override
217                 public Set<Location> apply(ClassFileFormatVersion cffv) {
218                     return (cffv.compareTo(ClassFileFormatVersion.latest()) >= 0
219                             && PreviewFeatures.isEnabled())
220                             ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET;
221                 }
222             }),
223 
224     /**
225      * The module flag {@code ACC_OPEN} with a mask value of {@code
226      * 0x0020}.
227      * @see java.lang.module.ModuleDescriptor#isOpen
228      */
229     OPEN(0x0000_0020, false, Location.SET_MODULE,
230          new Function<ClassFileFormatVersion, Set<Location>>() {
231              @Override
232              public Set<Location> apply(ClassFileFormatVersion cffv) {
233                  return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
234                      Location.SET_MODULE:
235                      Location.EMPTY_SET;}
236          }),
237 
238     /**
239      * The module requires flag {@code ACC_TRANSITIVE} with a mask
240      * value of {@code 0x0020}.
241      * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
242      */
243     TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
244                new Function<ClassFileFormatVersion, Set<Location>>() {
245                    @Override
246                    public Set<Location> apply(ClassFileFormatVersion cffv) {
247                        return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
248                            Location.SET_MODULE_REQUIRES:
249                            Location.EMPTY_SET;}
250                }),
251 
252     /**
253      * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
254      * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with
255      * a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
256      */
257     SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null),
258 
259     /**
260      * The module requires flag {@code ACC_STATIC_PHASE} with a mask
261      * value of {@code 0x0040}.
262      * @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
263      */
264     STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES,
265                  new Function<ClassFileFormatVersion, Set<Location>>() {
266                      @Override
267                      public Set<Location> apply(ClassFileFormatVersion cffv) {
268                          return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
269                              Location.SET_MODULE_REQUIRES:
270                              Location.EMPTY_SET;}
271                  }),
272 
273     /**
274      * The access flag {@code ACC_VOLATILE}, corresponding to the
275      * source modifier {@link Modifier#VOLATILE volatile}, with a mask
276      * value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
277      */
278     VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null),
279 
280     /**
281      * The access flag {@code ACC_BRIDGE} with a mask value of
282      * <code>{@value "0x%04x" Modifier#BRIDGE}</code>
283      * @see Method#isBridge()
284      */
285     BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD,
286            new Function<ClassFileFormatVersion, Set<Location>>() {
287                @Override
288                public Set<Location> apply(ClassFileFormatVersion cffv) {
289                    return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
290                        Location.SET_METHOD:
291                        Location.EMPTY_SET;}
292            }),
293 
294     /**
295      * The access flag {@code ACC_TRANSIENT}, corresponding to the
296      * source modifier {@link Modifier#TRANSIENT transient}, with a
297      * mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>.
298      */
299     TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, null),
300 
301     /**
302      * The access flag {@code ACC_VARARGS} with a mask value of
303      <code>{@value "0x%04x" Modifier#VARARGS}</code>.
304      * @see Executable#isVarArgs()
305      */
306     VARARGS(Modifier.VARARGS, false, Location.SET_METHOD,
307             new Function<ClassFileFormatVersion, Set<Location>>() {
308                 @Override
309                 public Set<Location> apply(ClassFileFormatVersion cffv) {
310                     return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
311                         Location.SET_METHOD:
312                         Location.EMPTY_SET;}
313             }),
314 
315     /**
316      * The access flag {@code ACC_NATIVE}, corresponding to the source
317      * modifier {@link Modifier#NATIVE native}, with a mask value of
318      * <code>{@value "0x%04x" Modifier#NATIVE}</code>.
319      */
320     NATIVE(Modifier.NATIVE, true, Location.SET_METHOD, null),
321 
322     /**
323      * The access flag {@code ACC_INTERFACE} with a mask value of
324      * {@code 0x0200}.
325      * @see Class#isInterface()
326      */
327     INTERFACE(Modifier.INTERFACE, false, Location.SET_CLASS_INNER_CLASS,
328               new Function<ClassFileFormatVersion, Set<Location>>() {
329                   @Override
330                   public Set<Location> apply(ClassFileFormatVersion cffv) {
331                       return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ?
332                           Location.SET_CLASS:
333                           Location.SET_CLASS_INNER_CLASS;}
334               }),
335 
336     /**
337      * The access flag {@code ACC_ABSTRACT}, corresponding to the
338      * source modifier {@link Modifier#ABSTRACT abstract}, with a mask
339      * value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>.
340      */
341     ABSTRACT(Modifier.ABSTRACT, true,
342              Location.SET_CLASS_METHOD_INNER_CLASS,
343              new Function<ClassFileFormatVersion, Set<Location>>() {
344                  @Override
345                  public Set<Location> apply(ClassFileFormatVersion cffv) {
346                      return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ?
347                          Location.SET_CLASS_METHOD:
348                          Location.SET_CLASS_METHOD_INNER_CLASS;}
349              }),
350 
351     /**
352      * The access flag {@code ACC_STRICT}, corresponding to the source
353      * modifier {@link Modifier#STRICT strictfp}, with a mask value of
354      * <code>{@value "0x%04x" Modifier#STRICT}</code>.
355      *
356      * @apiNote
357      * The {@code ACC_STRICT} access flag is defined for class file
358      * major versions 46 through 60, inclusive (JVMS {@jvms 4.6}),
359      * corresponding to Java SE 1.2 through 16.
360      */
361     STRICT(Modifier.STRICT, true, Location.EMPTY_SET,
362              new Function<ClassFileFormatVersion, Set<Location>>() {
363                @Override
364                public Set<Location> apply(ClassFileFormatVersion cffv) {
365                    return (cffv.compareTo(ClassFileFormatVersion.RELEASE_2)  >= 0 &&
366                            cffv.compareTo(ClassFileFormatVersion.RELEASE_16) <= 0) ?
367                        Location.SET_METHOD:
368                        Location.EMPTY_SET;}
369            }),
370 
371     /**
372      * The access flag {@code ACC_STRICT_INIT}, with a mask
373      * value of {@code 0x0800}.
374      *
375      * @jvms 4.5 Fields
376      * @since Valhalla
377      */
378     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS, reflective=true)
379     STRICT_INIT(Modifier.STRICT, false,
380             PreviewFeatures.isEnabled() ? Location.SET_FIELD : Location.EMPTY_SET,
381             new Function<ClassFileFormatVersion, Set<Location>>() {
382                 @Override
383                 public Set<Location> apply(ClassFileFormatVersion cffv) {
384                     return (cffv.compareTo(ClassFileFormatVersion.latest()) >= 0
385                             && PreviewFeatures.isEnabled())
386                             ? Location.SET_FIELD : Location.EMPTY_SET;
387                 }
388             }),
389 
390     /**
391      * The access flag {@code ACC_SYNTHETIC} with a mask value of
392      * <code>{@value "0x%04x" Modifier#SYNTHETIC}</code>.
393      * @see Class#isSynthetic()
394      * @see Executable#isSynthetic()
395      * @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC
396      */
397     SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9,
398               new Function<ClassFileFormatVersion, Set<Location>>() {
399                   @Override
400                   public Set<Location> apply(ClassFileFormatVersion cffv) {
401                       if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 )
402                           return Location.SET_SYNTHETIC_9;
403                       else {
404                           return
405                               switch(cffv) {
406                               case RELEASE_7 -> Location.SET_SYNTHETIC_7;
407                               case RELEASE_8 -> Location.SET_SYNTHETIC_8;
408                               default        -> Location.EMPTY_SET;
409                               };
410                       }
411                   }
412               }),
413 
414     /**
415      * The access flag {@code ACC_ANNOTATION} with a mask value of
416      * <code>{@value "0x%04x" Modifier#ANNOTATION}</code>.
417      * @see Class#isAnnotation()
418      */
419     ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS,
420                new Function<ClassFileFormatVersion, Set<Location>>() {
421                    @Override
422                    public Set<Location> apply(ClassFileFormatVersion cffv) {
423                        return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
424                            Location.SET_CLASS_INNER_CLASS:
425                            Location.EMPTY_SET;}
426                }),
427 
428     /**
429      * The access flag {@code ACC_ENUM} with a mask value of
430      * <code>{@value "0x%04x" Modifier#ENUM}</code>.
431      * @see Class#isEnum()
432      */
433     ENUM(Modifier.ENUM, false, Location.SET_CLASS_FIELD_INNER_CLASS,
434          new Function<ClassFileFormatVersion, Set<Location>>() {
435              @Override
436              public Set<Location> apply(ClassFileFormatVersion cffv) {
437                  return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
438                      Location.SET_CLASS_FIELD_INNER_CLASS:
439                      Location.EMPTY_SET;}
440          }),
441 
442     /**
443      * The access flag {@code ACC_MANDATED} with a mask value of
444      * <code>{@value "0x%04x" Modifier#MANDATED}</code>.
445      */
446     MANDATED(Modifier.MANDATED, false, Location.SET_MANDATED_9,
447              new Function<ClassFileFormatVersion, Set<Location>>() {
448                  @Override
449                  public Set<Location> apply(ClassFileFormatVersion cffv) {
450                      if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) {
451                          return Location.SET_MANDATED_9;
452                      } else {
453                          return (cffv == ClassFileFormatVersion.RELEASE_8) ?
454                              Location.SET_METHOD_PARAM:
455                              Location.EMPTY_SET;
456                      }
457                  }
458              }),
459 
460     /**
461      * The access flag {@code ACC_MODULE} with a mask value of {@code
462      * 0x8000}.
463      */
464     MODULE(0x0000_8000, false, Location.SET_CLASS,
465            new Function<ClassFileFormatVersion, Set<Location>>() {
466                @Override
467                public Set<Location> apply(ClassFileFormatVersion cffv) {
468                    return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
469                        Location.SET_CLASS:
470                        Location.EMPTY_SET;}
471            })
472     ;
473 
474     // May want to override toString for a different enum constant ->
475     // name mapping.
476 
477     private final int mask;
478     private final boolean sourceModifier;
479 
480     // Intentionally using Set rather than EnumSet since EnumSet is
481     // mutable.
482     private final Set<Location> locations;
483     // Lambda to implement locations(ClassFileFormatVersion cffv)
484     private final Function<ClassFileFormatVersion, Set<Location>> cffvToLocations;
485 
486     private AccessFlag(int mask,
487                        boolean sourceModifier,
488                        Set<Location> locations,
489                        Function<ClassFileFormatVersion, Set<Location>> cffvToLocations) {
490         this.mask = mask;
491         this.sourceModifier = sourceModifier;
492         this.locations = locations;
493         this.cffvToLocations = cffvToLocations;
494     }
495 
496     /**
497      * {@return the corresponding integer mask for the access flag}
498      */
499     public int mask() {
500         return mask;
501     }
502 
503     /**
504      * {@return whether or not the flag has a directly corresponding
505      * modifier in the Java programming language}
506      */
507     public boolean sourceModifier() {
508         return sourceModifier;
509     }
510 
511     /**
512      * {@return kinds of constructs the flag can be applied to in the
513      * latest class file format version}
514      */
515     public Set<Location> locations() {
516         return locations;
517     }
518 
519     /**
520      * {@return kinds of constructs the flag can be applied to in the
521      * given class file format version}
522      * @param cffv the class file format version to use
523      * @throws NullPointerException if the parameter is {@code null}
524      */
525     public Set<Location> locations(ClassFileFormatVersion cffv) {
526         Objects.requireNonNull(cffv);
527         if (cffvToLocations == null) {
528             return locations;
529         } else {
530             return cffvToLocations.apply(cffv);
531         }
532     }
533 
534     /**
535      * {@return an unmodifiable set of access flags for the given mask value
536      * appropriate for the location in question}
537      *
538      * @param mask bit mask of access flags
539      * @param location context to interpret mask value
540      * @throws IllegalArgumentException if the mask contains bit
541      * positions not supported for the location in question
542      */
543     public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
544         Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class);
545         for (var accessFlag : LocationToFlags.locationToFlags.get(location)) {
546             int accessMask = accessFlag.mask();
547             if ((mask & accessMask) != 0) {
548                 result.add(accessFlag);
549                 mask = mask & ~accessMask;
550                 if (mask == 0) {
551                     break;      // no more mask bits
552                 }
553             }
554         }
555         if (mask != 0) {
556             throw new IllegalArgumentException("Unmatched bit position 0x" +
557                                                Integer.toHexString(mask) +
558                                                " for location " + location);
559         }
560         return Collections.unmodifiableSet(result);
561     }
562 
563     /**
564      * {@return an unmodifiable set of access flags for the given mask value
565      * appropriate for the location in question}
566      *
567      * @param mask bit mask of access flags
568      * @param location context to interpret mask value
569      * @param cffv the class file format version
570      * @throws IllegalArgumentException if the mask contains bit
571      * positions not supported for the location in question
572      *
573      * @since Valhalla
574      */
575     public static Set<AccessFlag> maskToAccessFlags(int mask, Location location,
576                                                     ClassFileFormatVersion cffv) {
577         Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class);
578         for (var accessFlag : AccessFlag.values()) {
579             int accessMask = accessFlag.mask();
580             if ((mask & accessMask) != 0) {
581                 var locations = accessFlag.locations(cffv);
582                 if (locations.contains(location)) {
583                     result.add(accessFlag);
584                     mask = mask & ~accessMask;
585                     if (mask == 0) {
586                         break;      // no more mask bits
587                     }
588                 }
589             }
590         }
591         if (mask != 0) {
592             throw new IllegalArgumentException("Unmatched bit position 0x" +
593                                                Integer.toHexString(mask) +
594                                                " for location " + location +
595                                                " for class file format version " + cffv);
596         }
597         return Collections.unmodifiableSet(result);
598     }
599 
600 
601     /**
602      * A location within a class file where flags can be applied.
603      *
604      * Note that since these locations represent class file structures
605      * rather than language structures many language structures, such
606      * as constructors and interfaces, are <em>not</em> present.
607      * @since 20
608      */
609     public enum Location {
610         /**
611          * Class location.
612          * @jvms 4.1 The ClassFile Structure
613          */
614         CLASS,
615 
616         /**
617          * Field location.
618          * @jvms 4.5 Fields
619          */
620         FIELD,
621 
622         /**
623          * Method location.
624          * @jvms 4.6 Methods
625          */
626         METHOD,
627 
628         /**
629          * Inner class location.
630          * @jvms 4.7.6 The InnerClasses Attribute
631          */
632         INNER_CLASS,
633 
634         /**
635          * Method parameter location.
636          * @jvms 4.7.24 The MethodParameters Attribute
637          */
638         METHOD_PARAMETER,
639 
640         /**
641          * Module location
642          * @jvms 4.7.25 The Module Attribute
643          */
644         MODULE,
645 
646         /**
647          * Module requires location
648          * @jvms 4.7.25 The Module Attribute
649          */
650         MODULE_REQUIRES,
651 
652         /**
653          * Module exports location
654          * @jvms 4.7.25 The Module Attribute
655          */
656         MODULE_EXPORTS,
657 
658         /**
659          * Module opens location
660          * @jvms 4.7.25 The Module Attribute
661          */
662         MODULE_OPENS;
663 
664         // Repeated sets of locations used by AccessFlag constants
665         private static final Set<Location> EMPTY_SET = Set.of();
666         private static final Set<Location> SET_MODULE = Set.of(MODULE);
667         private static final Set<Location> SET_CLASS_METHOD_INNER_CLASS =
668             Set.of(CLASS, METHOD, INNER_CLASS);
669         private static final Set<Location> SET_CLASS_FIELD_METHOD =
670             Set.of(CLASS, FIELD, METHOD);
671         private static final Set<Location> SET_CLASS_FIELD_INNER_CLASS =
672             Set.of(CLASS, FIELD, INNER_CLASS);
673         private static final Set<Location> SET_CLASS_FIELD_METHOD_INNER_CLASS =
674             Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
675         private static final Set<Location> SET_CLASS_METHOD =
676             Set.of(CLASS, METHOD);
677         private static final Set<Location> SET_FIELD_METHOD =
678             Set.of(FIELD, METHOD);
679         private static final Set<Location> SET_FIELD_METHOD_INNER_CLASS =
680             Set.of(FIELD, METHOD, INNER_CLASS);
681         private static final Set<Location> SET_METHOD = Set.of(METHOD);
682         private static final Set<Location> SET_METHOD_PARAM = Set.of(METHOD_PARAMETER);
683         private static final Set<Location> SET_FIELD = Set.of(FIELD);
684         private static final Set<Location> SET_CLASS = Set.of(CLASS);
685         private static final Set<Location> SET_CLASS_INNER_CLASS =
686             Set.of(CLASS, INNER_CLASS);
687         private static final Set<Location> SET_MODULE_REQUIRES =
688             Set.of(MODULE_REQUIRES);
689         private static final Set<Location> SET_PUBLIC_1 =
690             Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
691         private static final Set<Location> SET_FINAL_8 =
692             Set.of(CLASS, FIELD, METHOD,
693                    INNER_CLASS,     /* added in 1.1 */
694                    METHOD_PARAMETER); /* added in 8 */
695         private static final Set<Location> SET_SYNTHETIC_7 =
696               Set.of(CLASS, FIELD, METHOD,
697                      INNER_CLASS);
698         private static final Set<Location> SET_SYNTHETIC_8 =
699               Set.of(CLASS, FIELD, METHOD,
700                      INNER_CLASS, METHOD_PARAMETER);
701         private static final Set<Location> SET_SYNTHETIC_9 =
702               // Added as an access flag in 7
703               Set.of(CLASS, FIELD, METHOD,
704                      INNER_CLASS,
705                      METHOD_PARAMETER, // Added in 8
706                      // Module-related items added in 9
707                      MODULE, MODULE_REQUIRES,
708                      MODULE_EXPORTS, MODULE_OPENS);
709         private static final Set<Location> SET_MANDATED_9 =
710             Set.of(METHOD_PARAMETER, // From 8
711                    // Starting in 9
712                    MODULE, MODULE_REQUIRES,
713                    MODULE_EXPORTS, MODULE_OPENS);
714     }
715 
716     private static class LocationToFlags {
717         private static Map<Location, Set<AccessFlag>> locationToFlags =
718             Map.ofEntries(entry(Location.CLASS,
719                                 Set.of(PUBLIC, FINAL, (PreviewFeatures.isEnabled() ? IDENTITY : SUPER),
720                                        INTERFACE, ABSTRACT,
721                                        SYNTHETIC, ANNOTATION,
722                                        ENUM, AccessFlag.MODULE)),
723                           entry(Location.FIELD,
724                                 PreviewFeatures.isEnabled() ?
725                                         // STRICT_INIT should be included only if preview is enabled
726                                         Set.of(PUBLIC, PRIVATE, PROTECTED,
727                                             STATIC, FINAL, VOLATILE,
728                                             TRANSIENT, SYNTHETIC, ENUM, STRICT_INIT) :
729                                         Set.of(PUBLIC, PRIVATE, PROTECTED,
730                                                 STATIC, FINAL, VOLATILE,
731                                                 TRANSIENT, SYNTHETIC, ENUM)),
732                           entry(Location.METHOD,
733                                 Set.of(PUBLIC, PRIVATE, PROTECTED,
734                                        STATIC, FINAL, SYNCHRONIZED,
735                                        BRIDGE, VARARGS, NATIVE,
736                                        ABSTRACT, STRICT, SYNTHETIC)),
737                           entry(Location.INNER_CLASS,
738                                           Set.of(PUBLIC, PRIVATE, PROTECTED, (PreviewFeatures.isEnabled() ? IDENTITY : SUPER),
739                                                   STATIC, FINAL, INTERFACE, ABSTRACT,
740                                                   SYNTHETIC, ANNOTATION, ENUM)),
741                           entry(Location.METHOD_PARAMETER,
742                                 Set.of(FINAL, SYNTHETIC, MANDATED)),
743                           entry(Location.MODULE,
744                                 Set.of(OPEN, SYNTHETIC, MANDATED)),
745                           entry(Location.MODULE_REQUIRES,
746                                 Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)),
747                           entry(Location.MODULE_EXPORTS,
748                                 Set.of(SYNTHETIC, MANDATED)),
749                           entry(Location.MODULE_OPENS,
750                                 Set.of(SYNTHETIC, MANDATED)));
751     }
752 }