35 import java.util.Set;
36
37 /*
38 * There are several patterns of access flag applicability. First, an
39 * access flag can be applied to the same set of locations for each
40 * class file format version. This is "invariant" usage. Second, an
41 * access flag can be defined for version N, therefore inapplicable
42 * for earlier versions, and then applied to the same locations for
43 * all subsequent versions. This is "step" usage. Finally, an access
44 * flag to have a more complicated pattern, having multiple steps of
45 * being allowed at more locations or even having locations removed if
46 * the access flag is retired.
47 *
48 * List of access flags and how they are tested:
49 *
50 * PUBLIC step
51 * PRIVATE step
52 * PROTECTED step
53 * STATIC step
54 * FINAL two-step
55 * SUPER invariant
56 * OPEN step
57 * TRANSITIVE step
58 * SYNCHRONIZED invariant
59 * STATIC_PHASE step
60 * VOLATILE invariant
61 * BRIDGE step
62 * TRANSIENT invariant
63 * VARARGS step
64 * NATIVE invariant
65 * INTERFACE step
66 * ABSTRACT step
67 * STRICT other
68 * SYNTHETIC other (three-step)
69 * ANNOTATION step
70 * ENUM step
71 * MANDATED two-step
72 * MODULE step
73 */
74
75 public class VersionedLocationsTest {
76 public static void main(String... args) throws Exception {
77 testInvariantAccessFlags();
78 testStepFunctionAccessFlags();
79 testTwoStepAccessFlags();
80 testSynthetic();
81 testStrict();
82 testLatestMatch();
83 testFlagVersionConsistency();
84 testLocationMaskFlagConsistency();
85 }
86
87 /**
88 * Invariant access flags have the same set of locations for each
89 * class file format version.
90 */
91 private static void testInvariantAccessFlags() {
92 Set<AccessFlag> invariantAccessFlags =
93 Set.of(SUPER, SYNCHRONIZED, VOLATILE, TRANSIENT, NATIVE);
94 for(var accessFlag : invariantAccessFlags) {
95 Set<AccessFlag.Location> expected = accessFlag.locations();
96
97 for(var cffv : ClassFileFormatVersion.values()) {
98 compareLocations(accessFlag.locations(), accessFlag, cffv);
99 }
100 }
101 }
102
103 private static void testStepFunctionAccessFlags() {
104 StepFunctionTC[] testCases = {
105 new StepFunctionTC(PUBLIC,
106 removeInnerClass(PUBLIC.locations()),
107 ClassFileFormatVersion.RELEASE_1),
108
109 new StepFunctionTC(PRIVATE,
110 removeInnerClass(PRIVATE.locations()),
111 ClassFileFormatVersion.RELEASE_1),
112
113 new StepFunctionTC(PROTECTED,
114 removeInnerClass(PROTECTED.locations()),
115 ClassFileFormatVersion.RELEASE_1),
116
117 new StepFunctionTC(STATIC,
118 removeInnerClass(STATIC.locations()),
119 ClassFileFormatVersion.RELEASE_1),
120
121 new StepFunctionTC(OPEN,
122 Set.of(),
123 ClassFileFormatVersion.RELEASE_9),
124
125 new StepFunctionTC(TRANSITIVE,
126 Set.of(),
127 ClassFileFormatVersion.RELEASE_9),
128
129 new StepFunctionTC(STATIC_PHASE,
130 Set.of(),
131 ClassFileFormatVersion.RELEASE_9),
132
133 new StepFunctionTC(BRIDGE,
134 Set.of(),
135 ClassFileFormatVersion.RELEASE_5),
136
137 new StepFunctionTC(VARARGS,
138 Set.of(),
139 ClassFileFormatVersion.RELEASE_5),
140
277
278 private static void testLatestMatch() {
279 // Verify accessFlag.locations() and
280 // accessFlag.locations(ClassFileFormatVersion.latest()) are
281 // consistent
282 var LATEST = ClassFileFormatVersion.latest();
283 for (var accessFlag : AccessFlag.values()) {
284 var locationSet = accessFlag.locations();
285 var locationLatestSet = accessFlag.locations(LATEST);
286 if (!locationSet.equals(locationLatestSet)) {
287 throw new RuntimeException("Unequal location sets for " + accessFlag);
288 }
289 }
290 }
291
292 private static void testFlagVersionConsistency() {
293 for (var flag : AccessFlag.values()) {
294 for (var location : AccessFlag.Location.values()) {
295 if (location.flags().contains(flag) != flag.locations().contains(location)) {
296 throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
297 "flag %s and location %s are inconsistent for the latest version"));
298 }
299 }
300 }
301 for (var cffv : ClassFileFormatVersion.values()) {
302 for (var flag : AccessFlag.values()) {
303 for (var location : AccessFlag.Location.values()) {
304 if (location.flags(cffv).contains(flag) != flag.locations(cffv).contains(location)) {
305 throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
306 "flag %s and location %s are inconsistent for class file version %s"));
307 }
308 }
309 }
310 }
311 }
312
313 private static void testLocationMaskFlagConsistency() {
314 for (var location : AccessFlag.Location.values()) {
315 if (!flagsAndMaskMatch(location.flags(), location.flagsMask())) {
316 throw new RuntimeException(String.format("Flags and mask mismatch for %s", location));
317 }
318 for (var cffv : ClassFileFormatVersion.values()) {
319 if (!flagsAndMaskMatch(location.flags(cffv), location.flagsMask(cffv))) {
320 throw new RuntimeException(String.format("Flags and mask mismatch for %s in %s", location, cffv));
321 }
322 }
323 }
324 }
325
326 private static boolean flagsAndMaskMatch(Set<AccessFlag> flags, int mask) {
|
35 import java.util.Set;
36
37 /*
38 * There are several patterns of access flag applicability. First, an
39 * access flag can be applied to the same set of locations for each
40 * class file format version. This is "invariant" usage. Second, an
41 * access flag can be defined for version N, therefore inapplicable
42 * for earlier versions, and then applied to the same locations for
43 * all subsequent versions. This is "step" usage. Finally, an access
44 * flag to have a more complicated pattern, having multiple steps of
45 * being allowed at more locations or even having locations removed if
46 * the access flag is retired.
47 *
48 * List of access flags and how they are tested:
49 *
50 * PUBLIC step
51 * PRIVATE step
52 * PROTECTED step
53 * STATIC step
54 * FINAL two-step
55 * SUPER step
56 * OPEN step
57 * TRANSITIVE step
58 * SYNCHRONIZED invariant
59 * STATIC_PHASE step
60 * VOLATILE invariant
61 * BRIDGE step
62 * TRANSIENT invariant
63 * VARARGS step
64 * NATIVE invariant
65 * INTERFACE step
66 * ABSTRACT step
67 * STRICT other
68 * SYNTHETIC other (three-step)
69 * ANNOTATION step
70 * ENUM step
71 * MANDATED two-step
72 * MODULE step
73 */
74
75 public class VersionedLocationsTest {
76 public static void main(String... args) throws Exception {
77 testInvariantAccessFlags();
78 testStepFunctionAccessFlags();
79 testTwoStepAccessFlags();
80 testSynthetic();
81 testStrict();
82 testLatestMatch();
83 testFlagVersionConsistency();
84 testLocationMaskFlagConsistency();
85 }
86
87 /**
88 * Invariant access flags have the same set of locations for each
89 * class file format version.
90 */
91 private static void testInvariantAccessFlags() {
92 Set<AccessFlag> invariantAccessFlags =
93 Set.of(SYNCHRONIZED, VOLATILE, TRANSIENT, NATIVE);
94 for(var accessFlag : invariantAccessFlags) {
95 Set<AccessFlag.Location> expected = accessFlag.locations();
96
97 for(var cffv : ClassFileFormatVersion.values()) {
98 compareLocations(accessFlag.locations(), accessFlag, cffv);
99 }
100 }
101 }
102
103 private static void testStepFunctionAccessFlags() {
104 StepFunctionTC[] testCases = {
105 new StepFunctionTC(PUBLIC,
106 removeInnerClass(PUBLIC.locations()),
107 ClassFileFormatVersion.RELEASE_1),
108
109 new StepFunctionTC(PRIVATE,
110 removeInnerClass(PRIVATE.locations()),
111 ClassFileFormatVersion.RELEASE_1),
112
113 new StepFunctionTC(PROTECTED,
114 removeInnerClass(PROTECTED.locations()),
115 ClassFileFormatVersion.RELEASE_1),
116
117 new StepFunctionTC(STATIC,
118 removeInnerClass(STATIC.locations()),
119 ClassFileFormatVersion.RELEASE_1),
120
121 new StepFunctionTC(SUPER,
122 Set.of(AccessFlag.Location.CLASS),
123 ClassFileFormatVersion.RELEASE_22),
124
125 new StepFunctionTC(OPEN,
126 Set.of(),
127 ClassFileFormatVersion.RELEASE_9),
128
129 new StepFunctionTC(TRANSITIVE,
130 Set.of(),
131 ClassFileFormatVersion.RELEASE_9),
132
133 new StepFunctionTC(STATIC_PHASE,
134 Set.of(),
135 ClassFileFormatVersion.RELEASE_9),
136
137 new StepFunctionTC(BRIDGE,
138 Set.of(),
139 ClassFileFormatVersion.RELEASE_5),
140
141 new StepFunctionTC(VARARGS,
142 Set.of(),
143 ClassFileFormatVersion.RELEASE_5),
144
281
282 private static void testLatestMatch() {
283 // Verify accessFlag.locations() and
284 // accessFlag.locations(ClassFileFormatVersion.latest()) are
285 // consistent
286 var LATEST = ClassFileFormatVersion.latest();
287 for (var accessFlag : AccessFlag.values()) {
288 var locationSet = accessFlag.locations();
289 var locationLatestSet = accessFlag.locations(LATEST);
290 if (!locationSet.equals(locationLatestSet)) {
291 throw new RuntimeException("Unequal location sets for " + accessFlag);
292 }
293 }
294 }
295
296 private static void testFlagVersionConsistency() {
297 for (var flag : AccessFlag.values()) {
298 for (var location : AccessFlag.Location.values()) {
299 if (location.flags().contains(flag) != flag.locations().contains(location)) {
300 throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
301 "flag %s and location %s are inconsistent for the latest version", flag, location));
302 }
303 }
304 }
305 for (var cffv : ClassFileFormatVersion.values()) {
306 for (var flag : AccessFlag.values()) {
307 for (var location : AccessFlag.Location.values()) {
308 if (location.flags(cffv).contains(flag) != flag.locations(cffv).contains(location)) {
309 throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
310 "flag %s and location %s are inconsistent for class file version %s", flag, location, cffv));
311 }
312 }
313 }
314 }
315 }
316
317 private static void testLocationMaskFlagConsistency() {
318 for (var location : AccessFlag.Location.values()) {
319 if (!flagsAndMaskMatch(location.flags(), location.flagsMask())) {
320 throw new RuntimeException(String.format("Flags and mask mismatch for %s", location));
321 }
322 for (var cffv : ClassFileFormatVersion.values()) {
323 if (!flagsAndMaskMatch(location.flags(cffv), location.flagsMask(cffv))) {
324 throw new RuntimeException(String.format("Flags and mask mismatch for %s in %s", location, cffv));
325 }
326 }
327 }
328 }
329
330 private static boolean flagsAndMaskMatch(Set<AccessFlag> flags, int mask) {
|