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 the current class file format version}
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 defined for the location in the current class file format
381 * @throws NullPointerException if {@code location} is {@code null}
382 */
383 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
384 var definition = findDefinition(location); // null checks location
385 int unmatchedMask = mask & (~location.flagsMask());
386 if (unmatchedMask != 0) {
387 throw new IllegalArgumentException("Unmatched bit position 0x" +
388 Integer.toHexString(unmatchedMask) +
389 " for location " + location);
390 }
391 return new AccessFlagSet(definition, mask);
392 }
393
394 /**
395 * {@return an unmodifiable set of access flags for the given mask value
396 * appropriate for the location in the given class file format version}
397 *
398 * @param mask bit mask of access flags
399 * @param location context to interpret mask value
400 * @param cffv the class file format to interpret mask value
401 * @throws IllegalArgumentException if the mask contains bit
402 * positions not defined for the location in the given class file format
403 * @throws NullPointerException if {@code location} or {@code cffv} is {@code null}
404 * @since 25
405 */
406 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, ClassFileFormatVersion cffv) {
407 var definition = findDefinition(location); // null checks location
408 int unmatchedMask = mask & (~location.flagsMask(cffv)); // null checks cffv
409 if (unmatchedMask != 0) {
410 throw new IllegalArgumentException("Unmatched bit position 0x" +
411 Integer.toHexString(unmatchedMask) +
412 " for location " + location +
413 " for class file format " + cffv);
414 }
415 return new AccessFlagSet(definition, mask);
416 }
417
418 /**
419 * A location within a {@code class} file where flags can be applied.
420 * <p>
421 * Note that since these locations represent {@code class} file structures
422 * rather than language structures, many language structures, such
423 * as constructors and interfaces, are <em>not</em> present.
424 * @since 20
425 */
426 public enum Location {
427 /**
428 * Class location.
429 *
430 * @see Class#accessFlags()
431 * @see ClassModel#flags()
432 * @see Modifier#classModifiers()
433 * @see Modifier#interfaceModifiers()
434 * @jvms 4.1 The {@code ClassFile} Structure
435 */
436 CLASS(ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
437 ACC_INTERFACE | ACC_ABSTRACT |
438 ACC_SYNTHETIC | ACC_ANNOTATION |
439 ACC_ENUM | ACC_MODULE,
440 List.of(Map.entry(RELEASE_8, // no module
441 ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
442 ACC_INTERFACE | ACC_ABSTRACT |
443 ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
444 Map.entry(RELEASE_4, // no synthetic, annotation, enum
445 ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
446 ACC_INTERFACE | ACC_ABSTRACT))),
447
448 /**
449 * Field location.
450 *
451 * @see Field#accessFlags()
452 * @see FieldModel#flags()
453 * @see Modifier#fieldModifiers()
454 * @jvms 4.5 Fields
455 */
456 FIELD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
457 ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
458 ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM,
459 List.of(Map.entry(RELEASE_4, // no synthetic, enum
460 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
461 ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
462 ACC_TRANSIENT))),
463
464 /**
465 * Method location.
466 *
467 * @see Executable#accessFlags()
468 * @see MethodModel#flags()
469 * @see Modifier#methodModifiers()
470 * @see Modifier#constructorModifiers()
471 * @jvms 4.6 Methods
472 */
473 METHOD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
474 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
475 ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
476 ACC_ABSTRACT | ACC_SYNTHETIC,
477 List.of(Map.entry(RELEASE_16, // had strict
478 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
479 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
480 ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
481 ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC),
482 Map.entry(RELEASE_4, // no bridge, varargs, synthetic
483 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
484 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
485 ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT),
486 Map.entry(RELEASE_1, // no strict
487 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
488 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
489 ACC_NATIVE | ACC_ABSTRACT))),
490
491 /**
492 * Inner class location.
493 *
494 * @see Class#accessFlags()
495 * @see InnerClassInfo#flags()
496 * @see Modifier#classModifiers()
497 * @see Modifier#interfaceModifiers()
498 * @jvms 4.7.6 The {@code InnerClasses} Attribute
499 */
500 INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
501 ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT |
502 ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM,
503 List.of(Map.entry(RELEASE_4, // no synthetic, annotation, enum
504 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
505 ACC_STATIC | ACC_FINAL | ACC_INTERFACE |
506 ACC_ABSTRACT),
507 Map.entry(RELEASE_0, 0))), // did not exist
508
509 /**
510 * Method parameter location.
511 *
512 * @see Parameter#accessFlags()
513 * @see MethodParameterInfo#flags()
514 * @see Modifier#parameterModifiers()
515 * @jvms 4.7.24 The {@code MethodParameters} Attribute
516 */
517 METHOD_PARAMETER(ACC_FINAL | ACC_SYNTHETIC | ACC_MANDATED,
518 List.of(Map.entry(RELEASE_7, 0))), // did not exist
519
520 /**
521 * Module location.
522 *
523 * @see ModuleDescriptor#accessFlags()
524 * @see ModuleAttribute#moduleFlags()
525 * @jvms 4.7.25 The {@code Module} Attribute
526 */
527 MODULE(ACC_OPEN | ACC_SYNTHETIC | ACC_MANDATED,
528 List.of(Map.entry(RELEASE_8, 0))), // did not exist
529
530 /**
531 * Module requires location.
532 *
533 * @see ModuleDescriptor.Requires#accessFlags()
534 * @see ModuleRequireInfo#requiresFlags()
535 * @jvms 4.7.25 The {@code Module} Attribute
536 */
537 MODULE_REQUIRES(ACC_TRANSITIVE | ACC_STATIC_PHASE | ACC_SYNTHETIC | ACC_MANDATED,
538 List.of(Map.entry(RELEASE_8, 0))), // did not exist
539
540 /**
541 * Module exports location.
542 *
543 * @see ModuleDescriptor.Exports#accessFlags()
544 * @see ModuleExportInfo#exportsFlags()
545 * @jvms 4.7.25 The {@code Module} Attribute
546 */
547 MODULE_EXPORTS(ACC_SYNTHETIC | ACC_MANDATED,
548 List.of(Map.entry(RELEASE_8, 0))), // did not exist
549
550 /**
551 * Module opens location.
552 *
553 * @see ModuleDescriptor.Opens#accessFlags()
554 * @see ModuleOpenInfo#opensFlags()
555 * @jvms 4.7.25 The {@code Module} Attribute
556 */
557 MODULE_OPENS(ACC_SYNTHETIC | ACC_MANDATED,
558 List.of(Map.entry(RELEASE_8, 0))), // did not exist
559 ;
560
561 // Repeated sets of locations used by AccessFlag constants
562 private static final Set<Location> EMPTY_SET = Set.of();
563 private static final Set<Location> SET_MODULE = Set.of(MODULE);
564 private static final Set<Location> SET_CLASS_METHOD_INNER_CLASS =
565 Set.of(CLASS, METHOD, INNER_CLASS);
566 private static final Set<Location> SET_CLASS_FIELD_METHOD =
567 Set.of(CLASS, FIELD, METHOD);
568 private static final Set<Location> SET_CLASS_FIELD_INNER_CLASS =
569 Set.of(CLASS, FIELD, INNER_CLASS);
570 private static final Set<Location> SET_CLASS_FIELD_METHOD_INNER_CLASS =
571 Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
572 private static final Set<Location> SET_CLASS_METHOD =
573 Set.of(CLASS, METHOD);
574 private static final Set<Location> SET_FIELD_METHOD =
575 Set.of(FIELD, METHOD);
576 private static final Set<Location> SET_FIELD_METHOD_INNER_CLASS =
577 Set.of(FIELD, METHOD, INNER_CLASS);
578 private static final Set<Location> SET_METHOD = Set.of(METHOD);
579 private static final Set<Location> SET_METHOD_PARAM = Set.of(METHOD_PARAMETER);
580 private static final Set<Location> SET_FIELD = Set.of(FIELD);
581 private static final Set<Location> SET_CLASS = Set.of(CLASS);
582 private static final Set<Location> SET_CLASS_INNER_CLASS =
583 Set.of(CLASS, INNER_CLASS);
584 private static final Set<Location> SET_MODULE_REQUIRES =
585 Set.of(MODULE_REQUIRES);
586 private static final Set<Location> SET_FINAL_8 =
587 Set.of(CLASS, FIELD, METHOD,
588 INNER_CLASS, /* added in 1.1 */
589 METHOD_PARAMETER); /* added in 8 */
590 private static final Set<Location> SET_SYNTHETIC_5 =
591 Set.of(CLASS, FIELD, METHOD,
592 INNER_CLASS);
593 private static final Set<Location> SET_SYNTHETIC_8 =
594 Set.of(CLASS, FIELD, METHOD,
595 INNER_CLASS, METHOD_PARAMETER);
596 private static final Set<Location> SET_SYNTHETIC_9 =
597 // Added as an access flag in 5.0
598 Set.of(CLASS, FIELD, METHOD,
599 INNER_CLASS,
600 METHOD_PARAMETER, // Added in 8
601 // Module-related items added in 9
602 MODULE, MODULE_REQUIRES,
603 MODULE_EXPORTS, MODULE_OPENS);
604 private static final Set<Location> SET_MANDATED_9 =
605 Set.of(METHOD_PARAMETER, // From 8
606 // Starting in 9
607 MODULE, MODULE_REQUIRES,
608 MODULE_EXPORTS, MODULE_OPENS);
609
610 private final int flagsMask;
611 private final List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks;
612
613 Location(int flagsMask,
614 List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks) {
615 this.flagsMask = flagsMask;
616 this.historicalFlagsMasks = ensureHistoryOrdered(historicalFlagsMasks);
617 }
618
619 // Ensures the historical versions are from newest to oldest and do not include the latest
620 // These 2 utilities reside in Location because Location must be initialized before AccessFlag
621 private static <T> List<Map.Entry<ClassFileFormatVersion, T>> ensureHistoryOrdered(
622 List<Map.Entry<ClassFileFormatVersion, T>> history) {
623 ClassFileFormatVersion lastVersion = ClassFileFormatVersion.latest();
624 for (var e : history) {
625 var historyVersion = e.getKey();
626 if (lastVersion.compareTo(historyVersion) <= 0) {
627 throw new IllegalArgumentException("Versions out of order");
628 }
629 lastVersion = historyVersion;
630 }
631 return history;
632 }
633
634 private static <T> T findInHistory(T candidate, List<Map.Entry<ClassFileFormatVersion, T>> history,
635 ClassFileFormatVersion cffv) {
636 Objects.requireNonNull(cffv);
637 for (var e : history) {
638 if (e.getKey().compareTo(cffv) < 0) {
639 // last version found was valid
640 return candidate;
641 }
642 candidate = e.getValue();
643 }
644 return candidate;
645 }
646
647 /**
648 * {@return the union of masks of all access flags defined for
649 * this location in the current class file format version}
650 * <p>
651 * This method returns {@code 0} if this location does not exist in
652 * the current class file format version.
653 *
654 * @since 25
655 */
656 public int flagsMask() {
657 return flagsMask;
658 }
659
660 /**
661 * {@return the union of masks of all access flags defined for
662 * this location in the given class file format version}
663 * <p>
664 * This method returns {@code 0} if this location does not exist in
665 * the given {@code cffv}.
666 *
667 * @param cffv the class file format version
668 * @throws NullPointerException if {@code cffv} is {@code null}
669 * @since 25
670 */
671 public int flagsMask(ClassFileFormatVersion cffv) {
672 return findInHistory(flagsMask, historicalFlagsMasks, cffv);
673 }
674
675 /**
676 * {@return the set of access flags defined for this location in the
677 * current class file format version} The set is immutable.
678 * <p>
679 * This method returns an empty set if this location does not exist
680 * in the current class file format version.
681 *
682 * @since 25
683 */
684 public Set<AccessFlag> flags() {
685 return new AccessFlagSet(findDefinition(this), flagsMask());
686 }
687
688 /**
689 * {@return the set of access flags defined for this location in the
690 * given class file format version} The set is immutable.
691 * <p>
692 * This method returns an empty set if this location does not exist
693 * in the given {@code cffv}.
694 *
695 * @param cffv the class file format version
696 * @throws NullPointerException if {@code cffv} is {@code null}
697 * @since 25
698 */
699 public Set<AccessFlag> flags(ClassFileFormatVersion cffv) {
700 // implicit null check cffv
701 return new AccessFlagSet(findDefinition(this), flagsMask(cffv));
702 }
703 }
704
705 private static AccessFlag[] createDefinition(AccessFlag... known) {
706 var ret = new AccessFlag[Character.SIZE];
707 for (var flag : known) {
708 var mask = flag.mask;
709 int pos = Integer.numberOfTrailingZeros(mask);
710 assert ret[pos] == null : ret[pos] + " " + flag;
711 ret[pos] = flag;
712 }
713 return ret;
714 }
715
716 // Will take extra args in the future for valhalla switch
717 private static AccessFlag[] findDefinition(Location location) {
718 return switch (location) {
719 case CLASS -> CLASS_FLAGS;
720 case FIELD -> FIELD_FLAGS;
721 case METHOD -> METHOD_FLAGS;
722 case INNER_CLASS -> INNER_CLASS_FLAGS;
723 case METHOD_PARAMETER -> METHOD_PARAMETER_FLAGS;
724 case MODULE -> MODULE_FLAGS;
725 case MODULE_REQUIRES -> MODULE_REQUIRES_FLAGS;
726 case MODULE_EXPORTS -> MODULE_EXPORTS_FLAGS;
727 case MODULE_OPENS -> MODULE_OPENS_FLAGS;
728 };
729 }
730
731 private static final @Stable AccessFlag[] // Can use stable array and lazy init in the future
732 CLASS_FLAGS = createDefinition(PUBLIC, FINAL, SUPER, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM, MODULE),
733 FIELD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, VOLATILE, TRANSIENT, SYNTHETIC, ENUM),
734 METHOD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SYNCHRONIZED, BRIDGE, VARARGS, NATIVE, ABSTRACT, STRICT, SYNTHETIC),
735 INNER_CLASS_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM),
736 METHOD_PARAMETER_FLAGS = createDefinition(FINAL, SYNTHETIC, MANDATED),
737 MODULE_FLAGS = createDefinition(OPEN, SYNTHETIC, MANDATED),
738 MODULE_REQUIRES_FLAGS = createDefinition(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED),
739 MODULE_EXPORTS_FLAGS = createDefinition(SYNTHETIC, MANDATED),
740 MODULE_OPENS_FLAGS = createDefinition(SYNTHETIC, MANDATED);
741
742 private static int undefinedMask(AccessFlag[] definition, int mask) {
743 assert definition.length == Character.SIZE;
744 int definedMask = 0;
745 for (int i = 0; i < Character.SIZE; i++) {
746 if (definition[i] != null) {
747 definedMask |= 1 << i;
748 }
749 }
750 return mask & ~definedMask;
751 }
752
753 private static final class AccessFlagSet extends AbstractSet<AccessFlag> {
754 private final @Stable AccessFlag[] definition;
755 private final int mask;
756
757 // all mutating methods throw UnsupportedOperationException
758 @Override public boolean add(AccessFlag e) { throw uoe(); }
759 @Override public boolean addAll(Collection<? extends AccessFlag> c) { throw uoe(); }
760 @Override public void clear() { throw uoe(); }
761 @Override public boolean remove(Object o) { throw uoe(); }
762 @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
763 @Override public boolean removeIf(Predicate<? super AccessFlag> filter) { throw uoe(); }
764 @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
765 private static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
766
767 private AccessFlagSet(AccessFlag[] definition, int mask) {
768 assert undefinedMask(definition, mask) == 0 : mask;
769 this.definition = definition;
770 this.mask = mask;
771 }
772
773 @Override
774 public Iterator<AccessFlag> iterator() {
775 return new AccessFlagIterator(definition, mask);
776 }
777
778 @Override
779 public void forEach(Consumer<? super AccessFlag> action) {
780 Objects.requireNonNull(action); // in case of empty
781 for (int i = 0; i < Character.SIZE; i++) {
782 if ((mask & (1 << i)) != 0) {
783 action.accept(definition[i]);
784 }
785 }
786 }
787
788 private static final class AccessFlagIterator implements Iterator<AccessFlag> {
789 private final @Stable AccessFlag[] definition;
790 private int remainingMask;
791
792 private AccessFlagIterator(AccessFlag[] definition, int remainingMask) {
793 this.definition = definition;
794 this.remainingMask = remainingMask;
795 }
796
797 @Override
798 public boolean hasNext() {
799 return remainingMask != 0;
800 }
801
802 @Override
803 public AccessFlag next() {
804 int flagBit = Integer.lowestOneBit(remainingMask);
805 if (flagBit == 0) {
806 throw new NoSuchElementException();
807 }
808 remainingMask &= ~flagBit;
809 return definition[Integer.numberOfTrailingZeros(flagBit)];
810 }
811 }
812
813 @Override
814 public int size() {
815 return Integer.bitCount(mask);
816 }
817
818 @Override
819 public boolean contains(Object o) {
820 if (Objects.requireNonNull(o) instanceof AccessFlag flag) {
821 int bit = flag.mask;
822 return (bit & mask) != 0 && definition[Integer.numberOfTrailingZeros(bit)] == flag;
823 }
824 return false;
825 }
826
827 @Override
828 public boolean isEmpty() {
829 return mask == 0;
830 }
831 }
832 }