1 /* 2 * Copyright (c) 2021, 2023, 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.misc.ValhallaFeatures; 29 30 import java.util.Collections; 31 import java.util.Objects; 32 import java.util.Map; 33 import java.util.Set; 34 import java.util.function.Function; 35 import static java.util.Map.entry; 36 37 /** 38 * Represents a JVM access or module-related flag on a runtime member, 39 * such as a {@linkplain Class class}, {@linkplain Field field}, or 40 * {@linkplain Executable method}. 41 * 42 * <P>JVM access and module-related flags are related to, but distinct 43 * from Java language {@linkplain Modifier modifiers}. Some modifiers 44 * and access flags have a one-to-one correspondence, such as {@code 45 * public}. In other cases, some language-level modifiers do 46 * <em>not</em> have an access flag, such as {@code sealed} (JVMS 47 * {@jvms 4.7.31}) and some access flags have no corresponding 48 * modifier, such as {@linkplain #SYNTHETIC synthetic}. 49 * 50 * <p>The values for the constants representing the access and module 51 * flags are taken from sections of <cite>The Java Virtual Machine 52 * Specification</cite> including {@jvms 4.1} (class access and 53 * property modifiers), {@jvms 4.5} (field access and property flags), 54 * {@jvms 4.6} (method access and property flags), {@jvms 4.7.6} 55 * (nested class access and property flags), {@jvms 4.7.24} (method 56 * parameters), and {@jvms 4.7.25} (module flags and requires, 57 * exports, and opens flags). 58 * 59 * <p>The {@linkplain #mask() mask} values for the different access 60 * flags are <em>not</em> distinct. Flags are defined for different 61 * kinds of JVM structures and the same bit position has different 62 * meanings in different contexts. For example, {@code 0x0000_0040} 63 * indicates a {@link #VOLATILE volatile} field but a {@linkplain 64 * #BRIDGE bridge method}; {@code 0x0000_0080} indicates a {@link 65 * #TRANSIENT transient} field but a {@linkplain #VARARGS variable 66 * arity (varargs)} method. 67 * 68 * @implSpec 69 * The access flag constants are ordered by non-decreasing mask 70 * value; that is the mask value of a constant is greater than or 71 * equal to the mask value of an immediate neighbor to its (syntactic) 72 * left. If new constants are added, this property will be 73 * maintained. That implies new constants will not necessarily be 74 * added at the end of the existing list. 75 * 76 * @apiNote 77 * The JVM class file format has a {@linkplain ClassFileFormatVersion new version} defined for each new 78 * {@linkplain Runtime.Version#feature() feature release}. A new class 79 * file version may define new access flags or retire old ones. {@code 80 * AccessFlag} is intended to model the set of access flags across 81 * class file format versions. The range of versions an access flag is 82 * recognized is not explicitly indicated in this API. See the current 83 * <cite>The Java Virtual Machine Specification</cite> for 84 * details. Unless otherwise indicated, access flags can be assumed to 85 * be recognized in the {@linkplain Runtime#version() current 86 * version}. 87 * 88 * @see java.lang.reflect.Modifier 89 * @see java.lang.module.ModuleDescriptor.Modifier 90 * @see java.lang.module.ModuleDescriptor.Requires.Modifier 91 * @see java.lang.module.ModuleDescriptor.Exports.Modifier 92 * @see java.lang.module.ModuleDescriptor.Opens.Modifier 93 * @see java.compiler/javax.lang.model.element.Modifier 94 * @since 20 95 */ 96 @SuppressWarnings("doclint:reference") // cross-module link 97 public enum AccessFlag { 98 // Note to maintainers: anonymous class instances are used rather 99 // than lambdas to initialize the functions used for the 100 // cffvToLocations field to avoid using lambdas too early in JDK 101 // initialization. 102 103 /** 104 * The access flag {@code ACC_PUBLIC}, corresponding to the source 105 * modifier {@link Modifier#PUBLIC public}, with a mask value of 106 * <code>{@value "0x%04x" Modifier#PUBLIC}</code>. 107 */ 108 PUBLIC(Modifier.PUBLIC, true, 109 Location.SET_PUBLIC_1, 110 new Function<ClassFileFormatVersion, Set<Location>>() { 111 @Override 112 public Set<Location> apply(ClassFileFormatVersion cffv) { 113 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 114 Location.SET_CLASS_FIELD_METHOD: 115 Location.SET_PUBLIC_1; 116 } 117 }), 118 119 /** 120 * The access flag {@code ACC_PRIVATE}, corresponding to the 121 * source modifier {@link Modifier#PRIVATE private}, with a mask 122 * value of <code>{@value "0x%04x" Modifier#PRIVATE}</code>. 123 */ 124 PRIVATE(Modifier.PRIVATE, true, Location.SET_FIELD_METHOD_INNER_CLASS, 125 new Function<ClassFileFormatVersion, Set<Location>>() { 126 @Override 127 public Set<Location> apply(ClassFileFormatVersion cffv) { 128 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 129 Location.SET_FIELD_METHOD: 130 Location.SET_FIELD_METHOD_INNER_CLASS; 131 } 132 }), 133 134 /** 135 * The access flag {@code ACC_PROTECTED}, corresponding to the 136 * source modifier {@link Modifier#PROTECTED protected}, with a mask 137 * value of <code>{@value "0x%04x" Modifier#PROTECTED}</code>. 138 */ 139 PROTECTED(Modifier.PROTECTED, true, Location.SET_FIELD_METHOD_INNER_CLASS, 140 new Function<ClassFileFormatVersion, Set<Location>>() { 141 @Override 142 public Set<Location> apply(ClassFileFormatVersion cffv) { 143 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 144 Location.SET_FIELD_METHOD: 145 Location.SET_FIELD_METHOD_INNER_CLASS; 146 } 147 }), 148 149 /** 150 * The access flag {@code ACC_STATIC}, corresponding to the source 151 * modifier {@link Modifier#STATIC static}, with a mask value of 152 * <code>{@value "0x%04x" Modifier#STATIC}</code>. 153 */ 154 STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS, 155 new Function<ClassFileFormatVersion, Set<Location>>() { 156 @Override 157 public Set<Location> apply(ClassFileFormatVersion cffv) { 158 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 159 Location.SET_FIELD_METHOD: 160 Location.SET_FIELD_METHOD_INNER_CLASS;} 161 }), 162 163 /** 164 * The access flag {@code ACC_FINAL}, corresponding to the source 165 * modifier {@link Modifier#FINAL final}, with a mask 166 * value of <code>{@value "0x%04x" Modifier#FINAL}</code>. 167 */ 168 FINAL(Modifier.FINAL, true, 169 Location.SET_FINAL_8, 170 new Function<ClassFileFormatVersion, Set<Location>>() { 171 @Override 172 public Set<Location> apply(ClassFileFormatVersion cffv) { 173 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_8) >= 0) { 174 return Location.SET_FINAL_8; 175 } else { 176 return (cffv == ClassFileFormatVersion.RELEASE_0) ? 177 Location.SET_CLASS_FIELD_METHOD : 178 Location.SET_CLASS_FIELD_METHOD_INNER_CLASS; 179 } 180 } 181 }), 182 183 /** 184 * The access flag {@code ACC_SUPER} with a mask value of {@code 185 * 0x0020}. 186 * 187 * @apiNote 188 * In Java SE 8 and above, the JVM treats the {@code ACC_SUPER} 189 * flag as set in every class file (JVMS {@jvms 4.1}). 190 * For class file versions up to Valhalla or if Valhalla is not enabled, 191 * {@code 0x0020} access flag bit is {@linkplain #SUPER SUPER access flag}; otherwise, 192 * the {@code 0x0020} access flag bit is {@linkplain #IDENTITY IDENTITY access flag}. 193 */ 194 SUPER(0x0000_0020, false, 195 ValhallaFeatures.isEnabled() ? Location.EMPTY_SET : Location.SET_CLASS, 196 new Function<ClassFileFormatVersion, Set<Location>>() { 197 @Override 198 public Set<Location> apply(ClassFileFormatVersion cffv) { 199 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_21) >= 0 && 200 ValhallaFeatures.isEnabled()) ? Location.EMPTY_SET : Location.SET_CLASS;} 201 }), 202 203 /** 204 * The access flag {@code ACC_IDENTITY}, corresponding to the 205 * source modifier {@link Modifier#IDENTITY identity}, with a mask 206 * value of <code>{@value "0x%04x" Modifier#IDENTITY}</code>. 207 * @jvms 4.1 -B. Class access and property modifiers 208 */ 209 IDENTITY(Modifier.IDENTITY, true, 210 ValhallaFeatures.isEnabled() ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET, 211 new Function<ClassFileFormatVersion, Set<Location>>() { 212 @Override 213 public Set<Location> apply(ClassFileFormatVersion cffv) { 214 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_21) >= 0 && 215 ValhallaFeatures.isEnabled()) ? Location.SET_CLASS_INNER_CLASS : Location.EMPTY_SET;} 216 }), 217 218 /** 219 * The module flag {@code ACC_OPEN} with a mask value of {@code 220 * 0x0020}. 221 * @see java.lang.module.ModuleDescriptor#isOpen 222 */ 223 OPEN(0x0000_0020, false, Location.SET_MODULE, 224 new Function<ClassFileFormatVersion, Set<Location>>() { 225 @Override 226 public Set<Location> apply(ClassFileFormatVersion cffv) { 227 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 228 Location.SET_MODULE: 229 Location.EMPTY_SET;} 230 }), 231 232 /** 233 * The module requires flag {@code ACC_TRANSITIVE} with a mask 234 * value of {@code 0x0020}. 235 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE 236 */ 237 TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES, 238 new Function<ClassFileFormatVersion, Set<Location>>() { 239 @Override 240 public Set<Location> apply(ClassFileFormatVersion cffv) { 241 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 242 Location.SET_MODULE_REQUIRES: 243 Location.EMPTY_SET;} 244 }), 245 246 /** 247 * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the 248 * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with 249 * a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>. 250 */ 251 SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null), 252 253 /** 254 * The module requires flag {@code ACC_STATIC_PHASE} with a mask 255 * value of {@code 0x0040}. 256 * @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC 257 */ 258 STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES, 259 new Function<ClassFileFormatVersion, Set<Location>>() { 260 @Override 261 public Set<Location> apply(ClassFileFormatVersion cffv) { 262 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 263 Location.SET_MODULE_REQUIRES: 264 Location.EMPTY_SET;} 265 }), 266 267 /** 268 * The access flag {@code ACC_VALUE}, corresponding to the 269 * source modifier {@link Modifier#VALUE value}, with a mask 270 * value of <code>{@value "0x%04x" Modifier#VALUE}</code>. 271 * @jvms 4.1 -B. Class access and property modifiers 272 */ 273 VALUE(Modifier.VALUE, true, Set.of(Location.CLASS, Location.INNER_CLASS), null), 274 275 /** 276 * The access flag {@code ACC_VOLATILE}, corresponding to the 277 * source modifier {@link Modifier#VOLATILE volatile}, with a mask 278 * value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>. 279 */ 280 VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null), 281 282 /** 283 * The access flag {@code ACC_BRIDGE} with a mask value of 284 * <code>{@value "0x%04x" Modifier#BRIDGE}</code> 285 * @see Method#isBridge() 286 */ 287 BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD, 288 new Function<ClassFileFormatVersion, Set<Location>>() { 289 @Override 290 public Set<Location> apply(ClassFileFormatVersion cffv) { 291 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 292 Location.SET_METHOD: 293 Location.EMPTY_SET;} 294 }), 295 296 /** 297 * The access flag {@code ACC_TRANSIENT}, corresponding to the 298 * source modifier {@link Modifier#TRANSIENT transient}, with a 299 * mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>. 300 */ 301 TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, null), 302 303 /** 304 * The access flag {@code ACC_VARARGS} with a mask value of 305 <code>{@value "0x%04x" Modifier#VARARGS}</code>. 306 * @see Executable#isVarArgs() 307 */ 308 VARARGS(Modifier.VARARGS, false, Location.SET_METHOD, 309 new Function<ClassFileFormatVersion, Set<Location>>() { 310 @Override 311 public Set<Location> apply(ClassFileFormatVersion cffv) { 312 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 313 Location.SET_METHOD: 314 Location.EMPTY_SET;} 315 }), 316 317 /** 318 * The access flag {@code ACC_NATIVE}, corresponding to the source 319 * modifier {@link Modifier#NATIVE native}, with a mask value of 320 * <code>{@value "0x%04x" Modifier#NATIVE}</code>. 321 */ 322 NATIVE(Modifier.NATIVE, true, Location.SET_METHOD, null), 323 324 /** 325 * The access flag {@code ACC_INTERFACE} with a mask value of 326 * {@code 0x0200}. 327 * @see Class#isInterface() 328 */ 329 INTERFACE(Modifier.INTERFACE, false, Location.SET_CLASS_INNER_CLASS, 330 new Function<ClassFileFormatVersion, Set<Location>>() { 331 @Override 332 public Set<Location> apply(ClassFileFormatVersion cffv) { 333 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ? 334 Location.SET_CLASS: 335 Location.SET_CLASS_INNER_CLASS;} 336 }), 337 338 /** 339 * The access flag {@code ACC_ABSTRACT}, corresponding to the 340 * source modifier {@link Modifier#ABSTRACT abstract}, with a mask 341 * value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>. 342 */ 343 ABSTRACT(Modifier.ABSTRACT, true, 344 Location.SET_CLASS_METHOD_INNER_CLASS, 345 new Function<ClassFileFormatVersion, Set<Location>>() { 346 @Override 347 public Set<Location> apply(ClassFileFormatVersion cffv) { 348 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ? 349 Location.SET_CLASS_METHOD: 350 Location.SET_CLASS_METHOD_INNER_CLASS;} 351 }), 352 353 /** 354 * The access flag {@code ACC_STRICT}, corresponding to the source 355 * modifier {@link Modifier#STRICT strictfp}, with a mask value of 356 * <code>{@value "0x%04x" Modifier#STRICT}</code>. 357 * 358 * @apiNote 359 * The {@code ACC_STRICT} access flag is defined for class file 360 * major versions 46 through 60, inclusive (JVMS {@jvms 4.6}), 361 * corresponding to Java SE 1.2 through 16. 362 */ 363 STRICT(Modifier.STRICT, true, Location.EMPTY_SET, 364 new Function<ClassFileFormatVersion, Set<Location>>() { 365 @Override 366 public Set<Location> apply(ClassFileFormatVersion cffv) { 367 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_2) >= 0 && 368 cffv.compareTo(ClassFileFormatVersion.RELEASE_16) <= 0) ? 369 Location.SET_METHOD: 370 Location.EMPTY_SET;} 371 }), 372 373 /** 374 * The access flag {@code ACC_SYNTHETIC} with a mask value of 375 * <code>{@value "0x%04x" Modifier#SYNTHETIC}</code>. 376 * @see Class#isSynthetic() 377 * @see Executable#isSynthetic() 378 * @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC 379 */ 380 SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9, 381 new Function<ClassFileFormatVersion, Set<Location>>() { 382 @Override 383 public Set<Location> apply(ClassFileFormatVersion cffv) { 384 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) 385 return Location.SET_SYNTHETIC_9; 386 else { 387 return 388 switch(cffv) { 389 case RELEASE_7 -> Location.SET_SYNTHETIC_7; 390 case RELEASE_8 -> Location.SET_SYNTHETIC_8; 391 default -> Location.EMPTY_SET; 392 }; 393 } 394 } 395 }), 396 397 /** 398 * The access flag {@code ACC_ANNOTATION} with a mask value of 399 * <code>{@value "0x%04x" Modifier#ANNOTATION}</code>. 400 * @see Class#isAnnotation() 401 */ 402 ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS, 403 new Function<ClassFileFormatVersion, Set<Location>>() { 404 @Override 405 public Set<Location> apply(ClassFileFormatVersion cffv) { 406 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 407 Location.SET_CLASS_INNER_CLASS: 408 Location.EMPTY_SET;} 409 }), 410 411 /** 412 * The access flag {@code ACC_ENUM} with a mask value of 413 * <code>{@value "0x%04x" Modifier#ENUM}</code>. 414 * @see Class#isEnum() 415 */ 416 ENUM(Modifier.ENUM, false, Location.SET_CLASS_FIELD_INNER_CLASS, 417 new Function<ClassFileFormatVersion, Set<Location>>() { 418 @Override 419 public Set<Location> apply(ClassFileFormatVersion cffv) { 420 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ? 421 Location.SET_CLASS_FIELD_INNER_CLASS: 422 Location.EMPTY_SET;} 423 }), 424 425 /** 426 * The access flag {@code ACC_MANDATED} with a mask value of 427 * <code>{@value "0x%04x" Modifier#MANDATED}</code>. 428 */ 429 MANDATED(Modifier.MANDATED, false, Location.SET_MANDATED_9, 430 new Function<ClassFileFormatVersion, Set<Location>>() { 431 @Override 432 public Set<Location> apply(ClassFileFormatVersion cffv) { 433 if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) { 434 return Location.SET_MANDATED_9; 435 } else { 436 return (cffv == ClassFileFormatVersion.RELEASE_8) ? 437 Location.SET_METHOD_PARAM: 438 Location.EMPTY_SET; 439 } 440 } 441 }), 442 443 /** 444 * The access flag {@code ACC_MODULE} with a mask value of {@code 445 * 0x8000}. 446 */ 447 MODULE(0x0000_8000, false, Location.SET_CLASS, 448 new Function<ClassFileFormatVersion, Set<Location>>() { 449 @Override 450 public Set<Location> apply(ClassFileFormatVersion cffv) { 451 return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ? 452 Location.SET_CLASS: 453 Location.EMPTY_SET;} 454 }) 455 ; 456 457 // May want to override toString for a different enum constant -> 458 // name mapping. 459 460 private final int mask; 461 private final boolean sourceModifier; 462 463 // Intentionally using Set rather than EnumSet since EnumSet is 464 // mutable. 465 private final Set<Location> locations; 466 // Lambda to implement locations(ClassFileFormatVersion cffv) 467 private final Function<ClassFileFormatVersion, Set<Location>> cffvToLocations; 468 469 private AccessFlag(int mask, 470 boolean sourceModifier, 471 Set<Location> locations, 472 Function<ClassFileFormatVersion, Set<Location>> cffvToLocations) { 473 this.mask = mask; 474 this.sourceModifier = sourceModifier; 475 this.locations = locations; 476 this.cffvToLocations = cffvToLocations; 477 } 478 479 /** 480 * {@return the corresponding integer mask for the access flag} 481 */ 482 public int mask() { 483 return mask; 484 } 485 486 /** 487 * {@return whether or not the flag has a directly corresponding 488 * modifier in the Java programming language} 489 */ 490 public boolean sourceModifier() { 491 return sourceModifier; 492 } 493 494 /** 495 * {@return kinds of constructs the flag can be applied to in the 496 * latest class file format version} 497 */ 498 public Set<Location> locations() { 499 return locations; 500 } 501 502 /** 503 * {@return kinds of constructs the flag can be applied to in the 504 * given class file format version} 505 * @param cffv the class file format version to use 506 * @throws NullPointerException if the parameter is {@code null} 507 */ 508 public Set<Location> locations(ClassFileFormatVersion cffv) { 509 Objects.requireNonNull(cffv); 510 if (cffvToLocations == null) { 511 return locations; 512 } else { 513 return cffvToLocations.apply(cffv); 514 } 515 } 516 517 /** 518 * {@return an unmodifiable set of access flags for the given mask value 519 * appropriate for the location in question} 520 * 521 * @param mask bit mask of access flags 522 * @param location context to interpret mask value 523 * @throws IllegalArgumentException if the mask contains bit 524 * positions not supported for the location in question 525 */ 526 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) { 527 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class); 528 for (var accessFlag : LocationToFlags.locationToFlags.get(location)) { 529 int accessMask = accessFlag.mask(); 530 if ((mask & accessMask) != 0) { 531 result.add(accessFlag); 532 mask = mask & ~accessMask; 533 if (mask == 0) { 534 break; // no more mask bits 535 } 536 } 537 } 538 if (mask != 0) { 539 throw new IllegalArgumentException("Unmatched bit position 0x" + 540 Integer.toHexString(mask) + 541 " for location " + location); 542 } 543 return Collections.unmodifiableSet(result); 544 } 545 546 /** 547 * {@return an unmodifiable set of access flags for the given mask value 548 * appropriate for the location in question} 549 * 550 * @param mask bit mask of access flags 551 * @param location context to interpret mask value 552 * @param cffv the class file format version 553 * @throws IllegalArgumentException if the mask contains bit 554 * positions not supported for the location in question 555 */ 556 public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, 557 ClassFileFormatVersion cffv) { 558 Set<AccessFlag> result = java.util.EnumSet.noneOf(AccessFlag.class); 559 for (var accessFlag : AccessFlag.values()) { 560 int accessMask = accessFlag.mask(); 561 if ((mask & accessMask) != 0) { 562 var locations = accessFlag.locations(cffv); 563 if (locations.contains(location)) { 564 result.add(accessFlag); 565 mask = mask & ~accessMask; 566 if (mask == 0) { 567 break; // no more mask bits 568 } 569 } 570 } 571 } 572 if (mask != 0) { 573 throw new IllegalArgumentException("Unmatched bit position 0x" + 574 Integer.toHexString(mask) + 575 " for location " + location + 576 " for class file format version " + cffv); 577 } 578 return Collections.unmodifiableSet(result); 579 } 580 581 582 /** 583 * A location within a class file where flags can be applied. 584 * 585 * Note that since these locations represent class file structures 586 * rather than language structures many language structures, such 587 * as constructors and interfaces, are <em>not</em> present. 588 * @since 20 589 */ 590 public enum Location { 591 /** 592 * Class location. 593 * @jvms 4.1 The ClassFile Structure 594 */ 595 CLASS, 596 597 /** 598 * Field location. 599 * @jvms 4.5 Fields 600 */ 601 FIELD, 602 603 /** 604 * Method location. 605 * @jvms 4.6 Method 606 */ 607 METHOD, 608 609 /** 610 * Inner class location. 611 * @jvms 4.7.6 The InnerClasses Attribute 612 */ 613 INNER_CLASS, 614 615 /** 616 * Method parameter loccation. 617 * @jvms 4.7.24. The MethodParameters Attribute 618 */ 619 METHOD_PARAMETER, 620 621 /** 622 * Module location 623 * @jvms 4.7.25. The Module Attribute 624 */ 625 MODULE, 626 627 /** 628 * Module requires location 629 * @jvms 4.7.25. The Module Attribute 630 */ 631 MODULE_REQUIRES, 632 633 /** 634 * Module exports location 635 * @jvms 4.7.25. The Module Attribute 636 */ 637 MODULE_EXPORTS, 638 639 /** 640 * Module opens location 641 * @jvms 4.7.25. The Module Attribute 642 */ 643 MODULE_OPENS; 644 645 // Repeated sets of locations used by AccessFlag constants 646 private static final Set<Location> EMPTY_SET = Set.of(); 647 private static final Set<Location> SET_MODULE = Set.of(MODULE); 648 private static final Set<Location> SET_CLASS_METHOD_INNER_CLASS = 649 Set.of(CLASS, METHOD, INNER_CLASS); 650 private static final Set<Location> SET_CLASS_FIELD_METHOD = 651 Set.of(CLASS, FIELD, METHOD); 652 private static final Set<Location> SET_CLASS_FIELD_INNER_CLASS = 653 Set.of(CLASS, FIELD, INNER_CLASS); 654 private static final Set<Location> SET_CLASS_FIELD_METHOD_INNER_CLASS = 655 Set.of(CLASS, FIELD, METHOD, INNER_CLASS); 656 private static final Set<Location> SET_CLASS_METHOD = 657 Set.of(CLASS, METHOD); 658 private static final Set<Location> SET_FIELD_METHOD = 659 Set.of(FIELD, METHOD); 660 private static final Set<Location> SET_FIELD_METHOD_INNER_CLASS = 661 Set.of(FIELD, METHOD, INNER_CLASS); 662 private static final Set<Location> SET_METHOD = Set.of(METHOD); 663 private static final Set<Location> SET_METHOD_PARAM = Set.of(METHOD_PARAMETER); 664 private static final Set<Location> SET_FIELD = Set.of(FIELD); 665 private static final Set<Location> SET_CLASS = Set.of(CLASS); 666 private static final Set<Location> SET_CLASS_INNER_CLASS = 667 Set.of(CLASS, INNER_CLASS); 668 private static final Set<Location> SET_MODULE_REQUIRES = 669 Set.of(MODULE_REQUIRES); 670 private static final Set<Location> SET_PUBLIC_1 = 671 Set.of(CLASS, FIELD, METHOD, INNER_CLASS); 672 private static final Set<Location> SET_FINAL_8 = 673 Set.of(CLASS, FIELD, METHOD, 674 INNER_CLASS, /* added in 1.1 */ 675 METHOD_PARAMETER); /* added in 8 */ 676 private static final Set<Location> SET_SYNTHETIC_7 = 677 Set.of(CLASS, FIELD, METHOD, 678 INNER_CLASS); 679 private static final Set<Location> SET_SYNTHETIC_8 = 680 Set.of(CLASS, FIELD, METHOD, 681 INNER_CLASS, METHOD_PARAMETER); 682 private static final Set<Location> SET_SYNTHETIC_9 = 683 // Added as an access flag in 7 684 Set.of(CLASS, FIELD, METHOD, 685 INNER_CLASS, 686 METHOD_PARAMETER, // Added in 8 687 // Module-related items added in 9 688 MODULE, MODULE_REQUIRES, 689 MODULE_EXPORTS, MODULE_OPENS); 690 private static final Set<Location> SET_MANDATED_9 = 691 Set.of(METHOD_PARAMETER, // From 8 692 // Starting in 9 693 MODULE, MODULE_REQUIRES, 694 MODULE_EXPORTS, MODULE_OPENS); 695 } 696 697 private static class LocationToFlags { 698 private static Map<Location, Set<AccessFlag>> locationToFlags = 699 Map.ofEntries(entry(Location.CLASS, 700 Set.of(PUBLIC, FINAL, IDENTITY, VALUE, 701 INTERFACE, ABSTRACT, 702 SYNTHETIC, ANNOTATION, 703 ENUM, AccessFlag.MODULE)), 704 entry(Location.FIELD, 705 Set.of(PUBLIC, PRIVATE, PROTECTED, 706 STATIC, FINAL, VOLATILE, 707 TRANSIENT, SYNTHETIC, ENUM)), 708 entry(Location.METHOD, 709 Set.of(PUBLIC, PRIVATE, PROTECTED, 710 STATIC, FINAL, SYNCHRONIZED, 711 BRIDGE, VARARGS, NATIVE, 712 ABSTRACT, STRICT, SYNTHETIC)), 713 entry(Location.INNER_CLASS, 714 Set.of(PUBLIC, PRIVATE, PROTECTED, IDENTITY, VALUE, 715 STATIC, FINAL, INTERFACE, ABSTRACT, 716 SYNTHETIC, ANNOTATION, ENUM)), 717 entry(Location.METHOD_PARAMETER, 718 Set.of(FINAL, SYNTHETIC, MANDATED)), 719 entry(Location.MODULE, 720 Set.of(OPEN, SYNTHETIC, MANDATED)), 721 entry(Location.MODULE_REQUIRES, 722 Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)), 723 entry(Location.MODULE_EXPORTS, 724 Set.of(SYNTHETIC, MANDATED)), 725 entry(Location.MODULE_OPENS, 726 Set.of(SYNTHETIC, MANDATED))); 727 } 728 }