1 /*
  2  * Copyright (c) 2021, 2025, 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 java.lang.classfile.ClassModel;
 29 import java.lang.classfile.FieldModel;
 30 import java.lang.classfile.MethodModel;
 31 import java.lang.classfile.attribute.InnerClassInfo;
 32 import java.lang.classfile.attribute.MethodParameterInfo;
 33 import java.lang.classfile.attribute.ModuleAttribute;
 34 import java.lang.classfile.attribute.ModuleExportInfo;
 35 import java.lang.classfile.attribute.ModuleOpenInfo;
 36 import java.lang.classfile.attribute.ModuleRequireInfo;
 37 import java.lang.module.ModuleDescriptor;
 38 import java.util.AbstractSet;
 39 import java.util.Collection;
 40 import java.util.Iterator;
 41 import java.util.List;
 42 import java.util.Map;
 43 import java.util.NoSuchElementException;
 44 import java.util.Objects;
 45 import java.util.Set;
 46 import java.util.function.Consumer;
 47 import java.util.function.Predicate;
 48 
 49 import jdk.internal.vm.annotation.Stable;
 50 
 51 import static java.lang.classfile.ClassFile.*;
 52 import static java.lang.reflect.ClassFileFormatVersion.*;
 53 
 54 /**
 55  * Represents a JVM access or module-related flag on a runtime member,
 56  * such as a {@linkplain Class class}, {@linkplain Field field}, or
 57  * {@linkplain Executable method}.
 58  *
 59  * <P>JVM access and module-related flags are related to, but distinct
 60  * from Java language {@linkplain Modifier modifiers}. Some modifiers
 61  * and access flags have a one-to-one correspondence, such as {@code
 62  * public}. In other cases, some language-level modifiers do
 63  * <em>not</em> have an access flag, such as {@code sealed} (JVMS
 64  * {@jvms 4.7.31}) and some access flags have no corresponding
 65  * modifier, such as {@linkplain #SYNTHETIC synthetic}.
 66  *
 67  * <p>The values for the constants representing the access and module
 68  * flags are taken from sections of <cite>The Java Virtual Machine
 69  * Specification</cite> including {@jvms 4.1} (class access and
 70  * property modifiers), {@jvms 4.5} (field access and property flags),
 71  * {@jvms 4.6} (method access and property flags), {@jvms 4.7.6}
 72  * (nested class access and property flags), {@jvms 4.7.24} (method
 73  * parameters), and {@jvms 4.7.25} (module flags and requires,
 74  * exports, and opens flags).
 75  *
 76  * <p>The {@linkplain #mask() mask} values for the different access
 77  * flags are <em>not</em> distinct. Flags are defined for different
 78  * kinds of JVM structures and the same bit position has different
 79  * meanings in different contexts. For example, {@code 0x0000_0040}
 80  * indicates a {@link #VOLATILE volatile} field but a {@linkplain
 81  * #BRIDGE bridge method}; {@code 0x0000_0080} indicates a {@link
 82  * #TRANSIENT transient} field but a {@linkplain #VARARGS variable
 83  * arity (varargs)} method.
 84  *
 85  * @implSpec
 86  * The access flag constants are ordered by non-decreasing mask
 87  * value; that is the mask value of a constant is greater than or
 88  * equal to the mask value of an immediate neighbor to its (syntactic)
 89  * left. If new constants are added, this property will be
 90  * maintained. That implies new constants will not necessarily be
 91  * added at the end of the existing list.
 92  *
 93  * @apiNote
 94  * The JVM class file format has a {@linkplain ClassFileFormatVersion new version} defined for each new
 95  * {@linkplain Runtime.Version#feature() feature release}. A new class
 96  * file version may define new access flags or retire old ones. {@code
 97  * AccessFlag} is intended to model the set of access flags across
 98  * class file format versions. The range of versions an access flag is
 99  * recognized is not explicitly indicated in this API. See the current
100  * <cite>The Java Virtual Machine Specification</cite> for
101  * details. Unless otherwise indicated, access flags can be assumed to
102  * be recognized in the {@linkplain Runtime#version() current
103  * version}.
104  *
105  * @see java.lang.reflect.Modifier
106  * @see java.lang.module.ModuleDescriptor.Modifier
107  * @see java.lang.module.ModuleDescriptor.Requires.Modifier
108  * @see java.lang.module.ModuleDescriptor.Exports.Modifier
109  * @see java.lang.module.ModuleDescriptor.Opens.Modifier
110  * @see java.compiler/javax.lang.model.element.Modifier
111  * @since 20
112  */
113 @SuppressWarnings("doclint:reference") // cross-module link
114 public enum AccessFlag {
115     /**
116      * The access flag {@code ACC_PUBLIC}, corresponding to the source
117      * modifier {@link Modifier#PUBLIC public}, with a mask value of
118      * <code>{@value "0x%04x" Modifier#PUBLIC}</code>.
119      */
120     PUBLIC(Modifier.PUBLIC, true,
121            Location.SET_CLASS_FIELD_METHOD_INNER_CLASS,
122            List.of(Map.entry(RELEASE_0, Location.SET_CLASS_FIELD_METHOD))),
123 
124     /**
125      * The access flag {@code ACC_PRIVATE}, corresponding to the
126      * source modifier {@link Modifier#PRIVATE private}, with a mask
127      * value of <code>{@value "0x%04x" Modifier#PRIVATE}</code>.
128      */
129     PRIVATE(Modifier.PRIVATE, true, Location.SET_FIELD_METHOD_INNER_CLASS,
130             List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
131 
132     /**
133      * The access flag {@code ACC_PROTECTED}, corresponding to the
134      * source modifier {@link Modifier#PROTECTED protected}, with a mask
135      * value of <code>{@value "0x%04x" Modifier#PROTECTED}</code>.
136      */
137     PROTECTED(Modifier.PROTECTED, true, Location.SET_FIELD_METHOD_INNER_CLASS,
138               List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
139 
140     /**
141      * The access flag {@code ACC_STATIC}, corresponding to the source
142      * modifier {@link Modifier#STATIC static}, with a mask value of
143      * <code>{@value "0x%04x" Modifier#STATIC}</code>.
144      */
145     STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS,
146            List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
147 
148     /**
149      * The access flag {@code ACC_FINAL}, corresponding to the source
150      * modifier {@link Modifier#FINAL final}, with a mask
151      * value of <code>{@value "0x%04x" Modifier#FINAL}</code>.
152      */
153     FINAL(Modifier.FINAL, true,
154           Location.SET_FINAL_8,
155           List.of(Map.entry(RELEASE_7, Location.SET_CLASS_FIELD_METHOD_INNER_CLASS),
156                   Map.entry(RELEASE_0, Location.SET_CLASS_FIELD_METHOD))),
157 
158     /**
159      * The access flag {@code ACC_SUPER} with a mask value of {@code
160      * 0x0020}.
161      *
162      * @apiNote
163      * In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
164      * flag as set in every class file (JVMS {@jvms 4.1}).
165      */
166     SUPER(0x0000_0020, false, Location.SET_CLASS, List.of()),
167 
168     /**
169      * The module flag {@code ACC_OPEN} with a mask value of {@code
170      * 0x0020}.
171      * @see java.lang.module.ModuleDescriptor#isOpen
172      */
173     OPEN(0x0000_0020, false, Location.SET_MODULE,
174          List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
175 
176     /**
177      * The module requires flag {@code ACC_TRANSITIVE} with a mask
178      * value of {@code 0x0020}.
179      * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
180      */
181     TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
182                List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
183 
184     /**
185      * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
186      * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with
187      * a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
188      */
189     SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, List.of()),
190 
191     /**
192      * The module requires flag {@code ACC_STATIC_PHASE} with a mask
193      * value of {@code 0x0040}.
194      * @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
195      */
196     STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES,
197                  List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
198 
199     /**
200      * The access flag {@code ACC_VOLATILE}, corresponding to the
201      * source modifier {@link Modifier#VOLATILE volatile}, with a mask
202      * value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
203      */
204     VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, List.of()),
205 
206     /**
207      * The access flag {@code ACC_BRIDGE} with a mask value of
208      * <code>{@value "0x%04x" Modifier#BRIDGE}</code>
209      * @see Method#isBridge()
210      */
211     BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD,
212            List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
213 
214     /**
215      * The access flag {@code ACC_TRANSIENT}, corresponding to the
216      * source modifier {@link Modifier#TRANSIENT transient}, with a
217      * mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>.
218      */
219     TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, List.of()),
220 
221     /**
222      * The access flag {@code ACC_VARARGS} with a mask value of
223      * <code>{@value "0x%04x" Modifier#VARARGS}</code>.
224      * @see Executable#isVarArgs()
225      */
226     VARARGS(Modifier.VARARGS, false, Location.SET_METHOD,
227             List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
228 
229     /**
230      * The access flag {@code ACC_NATIVE}, corresponding to the source
231      * modifier {@link Modifier#NATIVE native}, with a mask value of
232      * <code>{@value "0x%04x" Modifier#NATIVE}</code>.
233      */
234     NATIVE(Modifier.NATIVE, true, Location.SET_METHOD, List.of()),
235 
236     /**
237      * The access flag {@code ACC_INTERFACE} with a mask value of
238      * {@code 0x0200}.
239      * @see Class#isInterface()
240      */
241     INTERFACE(Modifier.INTERFACE, false, Location.SET_CLASS_INNER_CLASS,
242               List.of(Map.entry(RELEASE_0, Location.SET_CLASS))),
243 
244     /**
245      * The access flag {@code ACC_ABSTRACT}, corresponding to the
246      * source modifier {@link Modifier#ABSTRACT abstract}, with a mask
247      * value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>.
248      */
249     ABSTRACT(Modifier.ABSTRACT, true,
250              Location.SET_CLASS_METHOD_INNER_CLASS,
251              List.of(Map.entry(RELEASE_0, Location.SET_CLASS_METHOD))),
252 
253     /**
254      * The access flag {@code ACC_STRICT}, corresponding to the source
255      * modifier {@link Modifier#STRICT strictfp}, with a mask value of
256      * <code>{@value "0x%04x" Modifier#STRICT}</code>.
257      *
258      * @apiNote
259      * The {@code ACC_STRICT} access flag is defined for class file
260      * major versions 46 through 60, inclusive (JVMS {@jvms 4.6}),
261      * corresponding to Java SE 1.2 through 16.
262      */
263     STRICT(Modifier.STRICT, true, Location.EMPTY_SET,
264            List.of(Map.entry(RELEASE_16, Location.SET_METHOD),
265                    Map.entry(RELEASE_1, Location.EMPTY_SET))),
266 
267     /**
268      * The access flag {@code ACC_SYNTHETIC} with a mask value of
269      * <code>{@value "0x%04x" Modifier#SYNTHETIC}</code>.
270      * @see Class#isSynthetic()
271      * @see Executable#isSynthetic()
272      * @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC
273      */
274     SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9,
275               List.of(Map.entry(RELEASE_8, Location.SET_SYNTHETIC_8),
276                       Map.entry(RELEASE_7, Location.SET_SYNTHETIC_5),
277                       Map.entry(RELEASE_4, Location.EMPTY_SET))),
278 
279     /**
280      * The access flag {@code ACC_ANNOTATION} with a mask value of
281      * <code>{@value "0x%04x" Modifier#ANNOTATION}</code>.
282      * @see Class#isAnnotation()
283      */
284     ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS,
285                List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
286 
287     /**
288      * The access flag {@code ACC_ENUM} with a mask value of
289      * <code>{@value "0x%04x" Modifier#ENUM}</code>.
290      * @see Class#isEnum()
291      */
292     ENUM(Modifier.ENUM, false, Location.SET_CLASS_FIELD_INNER_CLASS,
293          List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
294 
295     /**
296      * The access flag {@code ACC_MANDATED} with a mask value of
297      * <code>{@value "0x%04x" Modifier#MANDATED}</code>.
298      */
299     MANDATED(Modifier.MANDATED, false, Location.SET_MANDATED_9,
300              List.of(Map.entry(RELEASE_8, Location.SET_METHOD_PARAM),
301                      Map.entry(RELEASE_7, Location.EMPTY_SET))),
302 
303     /**
304      * The access flag {@code ACC_MODULE} with a mask value of {@code
305      * 0x8000}.
306      */
307     MODULE(0x0000_8000, false, Location.SET_CLASS,
308            List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
309     ;
310 
311     // May want to override toString for a different enum constant ->
312     // name mapping.
313 
314     private final int mask;
315     private final boolean sourceModifier;
316 
317     // immutable
318     private final Set<Location> locations;
319     // historical locations up to a given version; immutable
320     private final List<Map.Entry<ClassFileFormatVersion, Set<Location>>> historicalLocations;
321 
322     private AccessFlag(int mask,
323                        boolean sourceModifier,
324                        Set<Location> locations,
325                        List<Map.Entry<ClassFileFormatVersion, Set<Location>>> historicalLocations) {
326         this.mask = mask;
327         this.sourceModifier = sourceModifier;
328         this.locations = locations;
329         this.historicalLocations = Location.ensureHistoryOrdered(historicalLocations);
330     }
331 
332     /**
333      * {@return the corresponding mask for the access flag}  The mask has
334      * exactly one bit set and is in the range of {@code char}.
335      */
336     public int mask() {
337         return mask;
338     }
339 
340     /**
341      * {@return whether or not this flag has a directly corresponding
342      * modifier in the Java programming language}
343      */
344     public boolean sourceModifier() {
345         return sourceModifier;
346     }
347 
348     /**
349      * {@return locations this flag can be applied to in the current class file
350      * format version}
351      * <p>
352      * This method returns an empty set if this flag is not defined in
353      * the current class file format version.
354      */
355     public Set<Location> locations() {
356         return locations;
357     }
358 
359     /**
360      * {@return locations this flag can be applied to in the given class file
361      * format version}
362      * <p>
363      * This method returns an empty set if this flag is not defined in
364      * the given {@code cffv}.
365      *
366      * @param cffv the class file format version to use
367      * @throws NullPointerException if the parameter is {@code null}
368      */
369     public Set<Location> locations(ClassFileFormatVersion cffv) {
370         return Location.findInHistory(locations, historicalLocations, cffv);
371     }
372 
373     /**
374      * {@return an unmodifiable set of access flags for the given mask value
375      * appropriate for the location in question}
376      *
377      * @param mask bit mask of access flags
378      * @param location context to interpret mask value
379      * @throws IllegalArgumentException if the mask contains bit
380      * positions not support for the location in question
381      */
382     public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
383         var definition = findDefinition(location);
384         int flagsMask = location.flagsMask();
385         int parsingMask = location == Location.METHOD ? flagsMask | ACC_STRICT : flagsMask; // flagMask lacks strictfp
386         int unmatchedMask = mask & (~parsingMask);
387         if (unmatchedMask != 0) {
388             throw new IllegalArgumentException("Unmatched bit position 0x" +
389                     Integer.toHexString(unmatchedMask) +
390                     " for location " + location);
391         }
392         return new AccessFlagSet(definition, mask);
393     }
394 
395     /**
396      * A location within a {@code class} file where flags can be applied.
397      * <p>
398      * Note that since these locations represent {@code class} file structures
399      * rather than language structures, many language structures, such
400      * as constructors and interfaces, are <em>not</em> present.
401      * @since 20
402      */
403     public enum Location {
404         /**
405          * Class location.
406          *
407          * @see Class#accessFlags()
408          * @see ClassModel#flags()
409          * @see Modifier#classModifiers()
410          * @see Modifier#interfaceModifiers()
411          * @jvms 4.1 The {@code ClassFile} Structure
412          */
413         CLASS(ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
414               ACC_INTERFACE | ACC_ABSTRACT |
415               ACC_SYNTHETIC | ACC_ANNOTATION |
416               ACC_ENUM | ACC_MODULE,
417               List.of(Map.entry(RELEASE_8, // no module
418                                 ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
419                                 ACC_INTERFACE | ACC_ABSTRACT |
420                                 ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
421                       Map.entry(RELEASE_4, // no synthetic, annotation, enum
422                                 ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
423                                 ACC_INTERFACE | ACC_ABSTRACT))),
424 
425         /**
426          * Field location.
427          *
428          * @see Field#accessFlags()
429          * @see FieldModel#flags()
430          * @see Modifier#fieldModifiers()
431          * @jvms 4.5 Fields
432          */
433         FIELD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
434               ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
435               ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM,
436               List.of(Map.entry(RELEASE_4, // no synthetic, enum
437                                 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
438                                 ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
439                                 ACC_TRANSIENT))),
440 
441         /**
442          * Method location.
443          *
444          * @see Executable#accessFlags()
445          * @see MethodModel#flags()
446          * @see Modifier#methodModifiers()
447          * @see Modifier#constructorModifiers()
448          * @jvms 4.6 Methods
449          */
450         METHOD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
451                ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
452                ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
453                ACC_ABSTRACT | ACC_SYNTHETIC,
454                List.of(Map.entry(RELEASE_16, // had strict
455                                  ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
456                                  ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
457                                  ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
458                                  ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC),
459                        Map.entry(RELEASE_4, // no bridge, varargs, synthetic
460                                  ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
461                                  ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
462                                  ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT),
463                        Map.entry(RELEASE_1, // no strict
464                                  ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
465                                  ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
466                                  ACC_NATIVE | ACC_ABSTRACT))),
467 
468         /**
469          * Inner class location.
470          *
471          * @see Class#accessFlags()
472          * @see InnerClassInfo#flags()
473          * @see Modifier#classModifiers()
474          * @see Modifier#interfaceModifiers()
475          * @jvms 4.7.6 The {@code InnerClasses} Attribute
476          */
477         INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
478                     ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT |
479                     ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM,
480                     List.of(Map.entry(RELEASE_4, // no synthetic, annotation, enum
481                             ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
482                             ACC_STATIC | ACC_FINAL | ACC_INTERFACE |
483                             ACC_ABSTRACT),
484                             Map.entry(RELEASE_0, 0))), // did not exist
485 
486         /**
487          * Method parameter location.
488          *
489          * @see Parameter#accessFlags()
490          * @see MethodParameterInfo#flags()
491          * @see Modifier#parameterModifiers()
492          * @jvms 4.7.24 The {@code MethodParameters} Attribute
493          */
494         METHOD_PARAMETER(ACC_FINAL | ACC_SYNTHETIC | ACC_MANDATED,
495                          List.of(Map.entry(RELEASE_7, 0))),  // did not exist
496 
497         /**
498          * Module location.
499          *
500          * @see ModuleDescriptor#accessFlags()
501          * @see ModuleAttribute#moduleFlags()
502          * @jvms 4.7.25 The {@code Module} Attribute
503          */
504         MODULE(ACC_OPEN | ACC_SYNTHETIC | ACC_MANDATED,
505                List.of(Map.entry(RELEASE_8, 0))),  // did not exist
506 
507         /**
508          * Module requires location.
509          *
510          * @see ModuleDescriptor.Requires#accessFlags()
511          * @see ModuleRequireInfo#requiresFlags()
512          * @jvms 4.7.25 The {@code Module} Attribute
513          */
514         MODULE_REQUIRES(ACC_TRANSITIVE | ACC_STATIC_PHASE | ACC_SYNTHETIC | ACC_MANDATED,
515                         List.of(Map.entry(RELEASE_8, 0))),  // did not exist
516 
517         /**
518          * Module exports location.
519          *
520          * @see ModuleDescriptor.Exports#accessFlags()
521          * @see ModuleExportInfo#exportsFlags()
522          * @jvms 4.7.25 The {@code Module} Attribute
523          */
524         MODULE_EXPORTS(ACC_SYNTHETIC | ACC_MANDATED,
525                        List.of(Map.entry(RELEASE_8, 0))),  // did not exist
526 
527         /**
528          * Module opens location.
529          *
530          * @see ModuleDescriptor.Opens#accessFlags()
531          * @see ModuleOpenInfo#opensFlags()
532          * @jvms 4.7.25 The {@code Module} Attribute
533          */
534         MODULE_OPENS(ACC_SYNTHETIC | ACC_MANDATED,
535                      List.of(Map.entry(RELEASE_8, 0))),  // did not exist
536         ;
537 
538         // Repeated sets of locations used by AccessFlag constants
539         private static final Set<Location> EMPTY_SET = Set.of();
540         private static final Set<Location> SET_MODULE = Set.of(MODULE);
541         private static final Set<Location> SET_CLASS_METHOD_INNER_CLASS =
542             Set.of(CLASS, METHOD, INNER_CLASS);
543         private static final Set<Location> SET_CLASS_FIELD_METHOD =
544             Set.of(CLASS, FIELD, METHOD);
545         private static final Set<Location> SET_CLASS_FIELD_INNER_CLASS =
546             Set.of(CLASS, FIELD, INNER_CLASS);
547         private static final Set<Location> SET_CLASS_FIELD_METHOD_INNER_CLASS =
548             Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
549         private static final Set<Location> SET_CLASS_METHOD =
550             Set.of(CLASS, METHOD);
551         private static final Set<Location> SET_FIELD_METHOD =
552             Set.of(FIELD, METHOD);
553         private static final Set<Location> SET_FIELD_METHOD_INNER_CLASS =
554             Set.of(FIELD, METHOD, INNER_CLASS);
555         private static final Set<Location> SET_METHOD = Set.of(METHOD);
556         private static final Set<Location> SET_METHOD_PARAM = Set.of(METHOD_PARAMETER);
557         private static final Set<Location> SET_FIELD = Set.of(FIELD);
558         private static final Set<Location> SET_CLASS = Set.of(CLASS);
559         private static final Set<Location> SET_CLASS_INNER_CLASS =
560             Set.of(CLASS, INNER_CLASS);
561         private static final Set<Location> SET_MODULE_REQUIRES =
562             Set.of(MODULE_REQUIRES);
563         private static final Set<Location> SET_FINAL_8 =
564             Set.of(CLASS, FIELD, METHOD,
565                    INNER_CLASS,     /* added in 1.1 */
566                    METHOD_PARAMETER); /* added in 8 */
567         private static final Set<Location> SET_SYNTHETIC_5 =
568               Set.of(CLASS, FIELD, METHOD,
569                      INNER_CLASS);
570         private static final Set<Location> SET_SYNTHETIC_8 =
571               Set.of(CLASS, FIELD, METHOD,
572                      INNER_CLASS, METHOD_PARAMETER);
573         private static final Set<Location> SET_SYNTHETIC_9 =
574               // Added as an access flag in 5.0
575               Set.of(CLASS, FIELD, METHOD,
576                      INNER_CLASS,
577                      METHOD_PARAMETER, // Added in 8
578                      // Module-related items added in 9
579                      MODULE, MODULE_REQUIRES,
580                      MODULE_EXPORTS, MODULE_OPENS);
581         private static final Set<Location> SET_MANDATED_9 =
582             Set.of(METHOD_PARAMETER, // From 8
583                    // Starting in 9
584                    MODULE, MODULE_REQUIRES,
585                    MODULE_EXPORTS, MODULE_OPENS);
586 
587         private final int flagsMask;
588         private final List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks;
589 
590         Location(int flagsMask,
591                  List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks) {
592             this.flagsMask = flagsMask;
593             this.historicalFlagsMasks = ensureHistoryOrdered(historicalFlagsMasks);
594         }
595 
596         // Ensures the historical versions are from newest to oldest and do not include the latest
597         // These 2 utilities reside in Location because Location must be initialized before AccessFlag
598         private static <T> List<Map.Entry<ClassFileFormatVersion, T>> ensureHistoryOrdered(
599                 List<Map.Entry<ClassFileFormatVersion, T>> history) {
600             ClassFileFormatVersion lastVersion = ClassFileFormatVersion.latest();
601             for (var e : history) {
602                 var historyVersion = e.getKey();
603                 if (lastVersion.compareTo(historyVersion) <= 0) {
604                     throw new IllegalArgumentException("Versions out of order");
605                 }
606                 lastVersion = historyVersion;
607             }
608             return history;
609         }
610 
611         private static <T> T findInHistory(T candidate, List<Map.Entry<ClassFileFormatVersion, T>> history,
612                                            ClassFileFormatVersion cffv) {
613             Objects.requireNonNull(cffv);
614             for (var e : history) {
615                 if (e.getKey().compareTo(cffv) < 0) {
616                     // last version found was valid
617                     return candidate;
618                 }
619                 candidate = e.getValue();
620             }
621             return candidate;
622         }
623 
624         /**
625          * {@return the union of masks of all access flags defined for
626          * this location in the current class file format version}
627          * <p>
628          * This method returns {@code 0} if this location does not exist in
629          * the current class file format version.
630          *
631          * @since 25
632          */
633         public int flagsMask() {
634             return flagsMask;
635         }
636 
637         /**
638          * {@return the union of masks of all access flags defined for
639          * this location in the given class file format version}
640          * <p>
641          * This method returns {@code 0} if this location does not exist in
642          * the given {@code cffv}.
643          *
644          * @param cffv the class file format version
645          * @throws NullPointerException if {@code cffv} is {@code null}
646          * @since 25
647          */
648         public int flagsMask(ClassFileFormatVersion cffv) {
649             return findInHistory(flagsMask, historicalFlagsMasks, cffv);
650         }
651 
652         /**
653          * {@return the set of access flags defined for this location in the
654          * current class file format version}  The set is immutable.
655          * <p>
656          * This method returns an empty set if this location does not exist
657          * in the current class file format version.
658          *
659          * @since 25
660          */
661         public Set<AccessFlag> flags() {
662             return new AccessFlagSet(findDefinition(this), flagsMask());
663         }
664 
665         /**
666          * {@return the set of access flags defined for this location in the
667          * given class file format version}  The set is immutable.
668          * <p>
669          * This method returns an empty set if this location does not exist
670          * in the given {@code cffv}.
671          *
672          * @param cffv the class file format version
673          * @throws NullPointerException if {@code cffv} is {@code null}
674          * @since 25
675          */
676         public Set<AccessFlag> flags(ClassFileFormatVersion cffv) {
677             // implicit null check cffv
678             return new AccessFlagSet(findDefinition(this), flagsMask(cffv));
679         }
680     }
681 
682     private static AccessFlag[] createDefinition(AccessFlag... known) {
683         var ret = new AccessFlag[Character.SIZE];
684         for (var flag : known) {
685             var mask = flag.mask;
686             int pos = Integer.numberOfTrailingZeros(mask);
687             assert ret[pos] == null : ret[pos] + " " + flag;
688             ret[pos] = flag;
689         }
690         return ret;
691     }
692 
693     // Will take extra args in the future for valhalla switch
694     private static AccessFlag[] findDefinition(Location location) {
695         return switch (location) {
696             case CLASS -> CLASS_FLAGS;
697             case FIELD -> FIELD_FLAGS;
698             case METHOD -> METHOD_FLAGS;
699             case INNER_CLASS -> INNER_CLASS_FLAGS;
700             case METHOD_PARAMETER -> METHOD_PARAMETER_FLAGS;
701             case MODULE -> MODULE_FLAGS;
702             case MODULE_REQUIRES -> MODULE_REQUIRES_FLAGS;
703             case MODULE_EXPORTS -> MODULE_EXPORTS_FLAGS;
704             case MODULE_OPENS -> MODULE_OPENS_FLAGS;
705         };
706     }
707 
708     private static final @Stable AccessFlag[] // Can use stable array and lazy init in the future
709             CLASS_FLAGS = createDefinition(PUBLIC, FINAL, SUPER, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM, MODULE),
710             FIELD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, VOLATILE, TRANSIENT, SYNTHETIC, ENUM),
711             METHOD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SYNCHRONIZED, BRIDGE, VARARGS, NATIVE, ABSTRACT, STRICT, SYNTHETIC),
712             INNER_CLASS_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM),
713             METHOD_PARAMETER_FLAGS = createDefinition(FINAL, SYNTHETIC, MANDATED),
714             MODULE_FLAGS = createDefinition(OPEN, SYNTHETIC, MANDATED),
715             MODULE_REQUIRES_FLAGS = createDefinition(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED),
716             MODULE_EXPORTS_FLAGS = createDefinition(SYNTHETIC, MANDATED),
717             MODULE_OPENS_FLAGS = createDefinition(SYNTHETIC, MANDATED);
718 
719     private static int undefinedMask(AccessFlag[] definition, int mask) {
720         assert definition.length == Character.SIZE;
721         int definedMask = 0;
722         for (int i = 0; i < Character.SIZE; i++) {
723             if (definition[i] != null) {
724                 definedMask |= 1 << i;
725             }
726         }
727         return mask & ~definedMask;
728     }
729 
730     private static final class AccessFlagSet extends AbstractSet<AccessFlag> {
731         private final @Stable AccessFlag[] definition;
732         private final int mask;
733 
734         // all mutating methods throw UnsupportedOperationException
735         @Override public boolean add(AccessFlag e) { throw uoe(); }
736         @Override public boolean addAll(Collection<? extends AccessFlag> c) { throw uoe(); }
737         @Override public void    clear() { throw uoe(); }
738         @Override public boolean remove(Object o) { throw uoe(); }
739         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
740         @Override public boolean removeIf(Predicate<? super AccessFlag> filter) { throw uoe(); }
741         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
742         private static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
743 
744         private AccessFlagSet(AccessFlag[] definition, int mask) {
745             assert undefinedMask(definition, mask) == 0 : mask;
746             this.definition = definition;
747             this.mask = mask;
748         }
749 
750         @Override
751         public Iterator<AccessFlag> iterator() {
752             return new AccessFlagIterator(definition, mask);
753         }
754 
755         @Override
756         public void forEach(Consumer<? super AccessFlag> action) {
757             Objects.requireNonNull(action); // in case of empty
758             for (int i = 0; i < Character.SIZE; i++) {
759                 if ((mask & (1 << i)) != 0) {
760                     action.accept(definition[i]);
761                 }
762             }
763         }
764 
765         private static final class AccessFlagIterator implements Iterator<AccessFlag> {
766             private final @Stable AccessFlag[] definition;
767             private int remainingMask;
768 
769             private AccessFlagIterator(AccessFlag[] definition, int remainingMask) {
770                 this.definition = definition;
771                 this.remainingMask = remainingMask;
772             }
773 
774             @Override
775             public boolean hasNext() {
776                 return remainingMask != 0;
777             }
778 
779             @Override
780             public AccessFlag next() {
781                 int flagBit = Integer.lowestOneBit(remainingMask);
782                 if (flagBit == 0) {
783                     throw new NoSuchElementException();
784                 }
785                 remainingMask &= ~flagBit;
786                 return definition[Integer.numberOfTrailingZeros(flagBit)];
787             }
788         }
789 
790         @Override
791         public int size() {
792             return Integer.bitCount(mask);
793         }
794 
795         @Override
796         public boolean contains(Object o) {
797             if (Objects.requireNonNull(o) instanceof AccessFlag flag) {
798                 int bit = flag.mask;
799                 return (bit & mask) != 0 && definition[Integer.numberOfTrailingZeros(bit)] == flag;
800             }
801             return false;
802         }
803 
804         @Override
805         public boolean isEmpty() {
806             return mask == 0;
807         }
808     }
809 }