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