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 }