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 the current class file format version} 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 defined for the location in the current class file format 413 * @throws NullPointerException if {@code location} is {@code null} 414 */ 415 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) { 416 var definition = findDefinition(location); // null checks location 417 int unmatchedMask = mask & (~location.flagsMask()); 418 if (unmatchedMask != 0) { 419 throw new IllegalArgumentException("Unmatched bit position 0x" + 420 Integer.toHexString(unmatchedMask) + 421 " for location " + location); 422 } 423 return new AccessFlagSet(definition, mask); 424 } 425 426 /** 427 * {@return an unmodifiable set of access flags for the given mask value 428 * appropriate for the location in the given class file format version} 429 * 430 * @param mask bit mask of access flags 431 * @param location context to interpret mask value 432 * @param cffv the class file format to interpret mask value 433 * @throws IllegalArgumentException if the mask contains bit 434 * positions not defined for the location in the given class file format 435 * @throws NullPointerException if {@code location} or {@code cffv} is {@code null} 436 * @since 25 437 */ 438 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, ClassFileFormatVersion cffv) { 439 var definition = findDefinition(location); // null checks location 440 int unmatchedMask = mask & (~location.flagsMask(cffv)); // null checks cffv 441 if (unmatchedMask != 0) { 442 throw new IllegalArgumentException("Unmatched bit position 0x" + 443 Integer.toHexString(unmatchedMask) + 444 " for location " + location + 445 " for class file format " + cffv); 446 } 447 return new AccessFlagSet(definition, mask); 448 } 449 450 /** 451 * A location within a {@code class} file where flags can be applied. 452 * <p> 453 * Note that since these locations represent {@code class} file structures 454 * rather than language structures, many language structures, such 455 * as constructors and interfaces, are <em>not</em> present. 456 * @since 20 457 */ 458 public enum Location { 459 /** 460 * Class location. 461 * 462 * @see Class#accessFlags() 463 * @see ClassModel#flags() 464 * @see Modifier#classModifiers() 465 * @see Modifier#interfaceModifiers() 466 * @jvms 4.1 The {@code ClassFile} Structure 467 */ 468 CLASS(ACC_PUBLIC | ACC_FINAL | (PreviewFeatures.isEnabled() ? ACC_IDENTITY : ACC_SUPER) | 469 ACC_INTERFACE | ACC_ABSTRACT | 470 ACC_SYNTHETIC | ACC_ANNOTATION | 471 ACC_ENUM | ACC_MODULE, 472 List.of(Map.entry(RELEASE_8, // no module 473 ACC_PUBLIC | ACC_FINAL | ACC_SUPER | 474 ACC_INTERFACE | ACC_ABSTRACT | 475 ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM), 476 Map.entry(RELEASE_4, // no synthetic, annotation, enum 477 ACC_PUBLIC | ACC_FINAL | ACC_SUPER | 478 ACC_INTERFACE | ACC_ABSTRACT))), 479 480 /** 481 * Field location. 482 * 483 * @see Field#accessFlags() 484 * @see FieldModel#flags() 485 * @see Modifier#fieldModifiers() 486 * @jvms 4.5 Fields 487 */ 488 FIELD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | 489 ACC_STATIC | ACC_FINAL | ACC_VOLATILE | 490 ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM | (PreviewFeatures.isEnabled() ? ACC_STRICT : 0), 491 List.of(Map.entry(RELEASE_4, // no synthetic, enum 492 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | 493 ACC_STATIC | ACC_FINAL | ACC_VOLATILE | 494 ACC_TRANSIENT))), 495 496 /** 497 * Method location. 498 * 499 * @see Executable#accessFlags() 500 * @see MethodModel#flags() 501 * @see Modifier#methodModifiers() 502 * @see Modifier#constructorModifiers() 503 * @jvms 4.6 Methods 504 */ 505 METHOD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | 506 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | 507 ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE | 508 ACC_ABSTRACT | ACC_SYNTHETIC, 509 List.of(Map.entry(RELEASE_16, // had strict 510 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | 511 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | 512 ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE | 513 ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC), 514 Map.entry(RELEASE_4, // no bridge, varargs, synthetic 515 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | 516 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | 517 ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT), 518 Map.entry(RELEASE_1, // no strict 519 ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | 520 ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | 521 ACC_NATIVE | ACC_ABSTRACT))), 522 523 /** 524 * Inner class location. 525 * 526 * @see Class#accessFlags() 527 * @see InnerClassInfo#flags() 528 * @see Modifier#classModifiers() 529 * @see Modifier#interfaceModifiers() 530 * @jvms 4.7.6 The {@code InnerClasses} Attribute 531 */ 532 INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | (PreviewFeatures.isEnabled() ? ACC_IDENTITY : ACC_SUPER) | 533 ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT | 534 ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM, 535 List.of(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 = ClassFileFormatVersion.latest(); 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; 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 new AccessFlagSet(findDefinition(this), flagsMask()); 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), 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) { 749 return switch (location) { 750 case CLASS -> CLASS_FLAGS; 751 case FIELD -> FIELD_FLAGS; 752 case METHOD -> METHOD_FLAGS; 753 case INNER_CLASS -> 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, (PreviewFeatures.isEnabled() ? IDENTITY : SUPER), INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM, MODULE), 764 FIELD_FLAGS = PreviewFeatures.isEnabled() ? // Using Valhalla 765 createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, VOLATILE, TRANSIENT, SYNTHETIC, ENUM, STRICT_INIT) : 766 createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, VOLATILE, TRANSIENT, SYNTHETIC, ENUM), 767 METHOD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SYNCHRONIZED, BRIDGE, VARARGS, NATIVE, ABSTRACT, STRICT, SYNTHETIC), 768 INNER_CLASS_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, (PreviewFeatures.isEnabled() ? IDENTITY : SUPER), STATIC, FINAL, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM), 769 METHOD_PARAMETER_FLAGS = createDefinition(FINAL, SYNTHETIC, MANDATED), 770 MODULE_FLAGS = createDefinition(OPEN, SYNTHETIC, MANDATED), 771 MODULE_REQUIRES_FLAGS = createDefinition(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED), 772 MODULE_EXPORTS_FLAGS = createDefinition(SYNTHETIC, MANDATED), 773 MODULE_OPENS_FLAGS = createDefinition(SYNTHETIC, MANDATED); 774 775 private static int undefinedMask(AccessFlag[] definition, int mask) { 776 assert definition.length == Character.SIZE; 777 int definedMask = 0; 778 for (int i = 0; i < Character.SIZE; i++) { 779 if (definition[i] != null) { 780 definedMask |= 1 << i; 781 } 782 } 783 return mask & ~definedMask; 784 } 785 786 private static final class AccessFlagSet extends AbstractSet<AccessFlag> { 787 private final @Stable AccessFlag[] definition; 788 private final int mask; 789 790 // all mutating methods throw UnsupportedOperationException 791 @Override public boolean add(AccessFlag e) { throw uoe(); } 792 @Override public boolean addAll(Collection<? extends AccessFlag> c) { throw uoe(); } 793 @Override public void clear() { throw uoe(); } 794 @Override public boolean remove(Object o) { throw uoe(); } 795 @Override public boolean removeAll(Collection<?> c) { throw uoe(); } 796 @Override public boolean removeIf(Predicate<? super AccessFlag> filter) { throw uoe(); } 797 @Override public boolean retainAll(Collection<?> c) { throw uoe(); } 798 private static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } 799 800 private AccessFlagSet(AccessFlag[] definition, int mask) { 801 assert undefinedMask(definition, mask) == 0 : mask; 802 this.definition = definition; 803 this.mask = mask; 804 } 805 806 @Override 807 public Iterator<AccessFlag> iterator() { 808 return new AccessFlagIterator(definition, mask); 809 } 810 811 @Override 812 public void forEach(Consumer<? super AccessFlag> action) { 813 Objects.requireNonNull(action); // in case of empty 814 for (int i = 0; i < Character.SIZE; i++) { 815 if ((mask & (1 << i)) != 0) { 816 action.accept(definition[i]); 817 } 818 } 819 } 820 821 private static final class AccessFlagIterator implements Iterator<AccessFlag> { 822 private final @Stable AccessFlag[] definition; 823 private int remainingMask; 824 825 private AccessFlagIterator(AccessFlag[] definition, int remainingMask) { 826 this.definition = definition; 827 this.remainingMask = remainingMask; 828 } 829 830 @Override 831 public boolean hasNext() { 832 return remainingMask != 0; 833 } 834 835 @Override 836 public AccessFlag next() { 837 int flagBit = Integer.lowestOneBit(remainingMask); 838 if (flagBit == 0) { 839 throw new NoSuchElementException(); 840 } 841 remainingMask &= ~flagBit; 842 return definition[Integer.numberOfTrailingZeros(flagBit)]; 843 } 844 } 845 846 @Override 847 public int size() { 848 return Integer.bitCount(mask); 849 } 850 851 @Override 852 public boolean contains(Object o) { 853 if (Objects.requireNonNull(o) instanceof AccessFlag flag) { 854 int bit = flag.mask; 855 return (bit & mask) != 0 && definition[Integer.numberOfTrailingZeros(bit)] == flag; 856 } 857 return false; 858 } 859 860 @Override 861 public boolean isEmpty() { 862 return mask == 0; 863 } 864 } 865 }