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