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