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