1 /*
2 * Copyright (c) 2026, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /* @test
25 * @bug 8351362
26 * @summary Unit Test for StrictProcessor super rewrite
27 * @enablePreview
28 * @library /test/lib
29 * @compile StrictProcessorSuperTest.java
30 * @run driver jdk.test.lib.helpers.StrictProcessor --deferSuperCall
31 * StrictProcessorSuperTest$Rec StrictProcessorSuperTest$Exp
32 * StrictProcessorSuperTest$Inner
33 * @run junit StrictProcessorSuperTest
34 */
35
36 import java.io.IOException;
37 import java.io.UncheckedIOException;
38 import java.lang.classfile.Attributes;
39 import java.lang.classfile.ClassFile;
40 import java.lang.classfile.ClassModel;
41 import java.lang.classfile.CompoundElement;
42 import java.lang.classfile.Instruction;
43 import java.lang.classfile.Opcode;
44 import java.lang.reflect.AccessFlag;
45 import java.lang.reflect.Modifier;
46 import java.util.ArrayList;
47 import java.util.stream.Stream;
48
49 import jdk.test.lib.helpers.StrictInit;
50 import org.junit.jupiter.params.ParameterizedTest;
51 import org.junit.jupiter.params.provider.MethodSource;
52
53 import static java.lang.classfile.ClassFile.*;
54 import static java.lang.constant.ConstantDescs.INIT_NAME;
55 import static org.junit.jupiter.api.Assertions.*;
56
57 class StrictProcessorSuperTest {
58 static Stream<Class<?>> testClasses() {
59 return Stream.of(Rec.class, Exp.class, Inner.class);
60 }
61
62 static Stream<ClassModel> testClassModels() {
63 return testClasses().map(cls -> {
64 try (var in = StrictProcessorSuperTest.class.getResourceAsStream("/" + cls.getName() + ".class")) {
65 return ClassFile.of().parse(in.readAllBytes());
66 } catch (IOException ex) {
67 throw new UncheckedIOException(ex);
68 }
69 });
70 }
71
72 @MethodSource("testClasses")
73 @ParameterizedTest
74 void testReflectRewrittenRecord(Class<?> cls) throws Throwable {
75 for (var field : cls.getDeclaredFields()) {
76 if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic())
77 continue;
78 assertEquals(ACC_PRIVATE | ACC_STRICT_INIT | ACC_FINAL, field.getModifiers(), () -> "For field: " + field.getName());
79 }
80 }
81
82 @MethodSource("testClassModels")
83 @ParameterizedTest
84 void testRewrittenStrictAccessInClassFile(ClassModel cm) throws Throwable {
85 for (var f : cm.fields()) {
86 if (f.flags().has(AccessFlag.STATIC) || f.flags().has(AccessFlag.SYNTHETIC))
87 continue;
88 assertEquals(ACC_PRIVATE | ACC_STRICT_INIT | ACC_FINAL, f.flags().flagsMask(), () -> "Field " + f);
89 }
90 }
91
92 @MethodSource("testClassModels")
93 @ParameterizedTest
94 void testRewrittenCtorBytecode(ClassModel cm) throws Throwable {
95 var ctor = cm.methods().stream().filter(m -> m.methodName().equalsString(INIT_NAME)).findFirst().orElseThrow();
96 var insts = new ArrayList<Instruction>();
97 ctor.findAttribute(Attributes.code()).orElseThrow().forEach(ce -> {
98 if (ce instanceof Instruction inst) {
99 insts.add(inst);
100 }
101 });
102 assertSame(Opcode.RETURN, insts.getLast().opcode());
103 assertSame(Opcode.INVOKESPECIAL, insts.get(insts.size() - 2).opcode());
104 }
105
106 record Rec(@StrictInit int a, @StrictInit long b) {
107 static final String NOISE = "noise";
108 }
109
110 static class Exp {
111 private @StrictInit final int a;
112 private @StrictInit final long b;
113
114 Exp(int a, long b) {
115 this.a = a;
116 this.b = b;
117 }
118 }
119
120 class Inner {
121 private @StrictInit final int a;
122 private @StrictInit final long b;
123
124 Inner(int a, long b) {
125 this.a = a;
126 this.b = b;
127 }
128
129 @Override
130 public String toString() {
131 return a + " " + StrictProcessorSuperTest.this + " " + b;
132 }
133 }
134 }