1 /*
2 * Copyright (c) 2024, 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 /*
25 * @test
26 * @modules jdk.incubator.code
27 * @run junit TestVarArgsInvoke
28 * @run main Unreflect TestVarArgsInvoke
29 * @run junit TestVarArgsInvoke
30 */
31
32 import jdk.incubator.code.Reflect;
33 import jdk.incubator.code.CodeTransformer;
34 import jdk.incubator.code.Op;
35 import jdk.incubator.code.dialect.core.CoreOp;
36 import jdk.incubator.code.dialect.java.JavaOp;
37 import jdk.incubator.code.dialect.java.JavaType;
38 import jdk.incubator.code.interpreter.Interpreter;
39 import org.junit.jupiter.api.Assertions;
40 import org.junit.jupiter.api.Test;
41
42 import java.lang.invoke.MethodHandles;
43 import java.lang.reflect.Method;
44 import java.util.Optional;
45 import java.util.stream.Stream;
46
47 public class TestVarArgsInvoke {
48
49 String m1(String... args) {
50 StringBuilder sb = new StringBuilder("m1");
51 for (String arg : args) {
52 sb.append(arg);
53 }
54 return sb.toString();
55 }
56
57 static String sm1(String... args) {
58 StringBuilder sb = new StringBuilder("sm1");
59 for (String arg : args) {
60 sb.append(arg);
61 }
62 return sb.toString();
63 }
64
65 String m2(String one, String... args) {
66 StringBuilder sb = new StringBuilder("m2");
67 sb.append(one);
68 for (String arg : args) {
69 sb.append(arg);
70 }
71 return sb.toString();
72 }
73
74 static String sm2(String one, String... args) {
75 StringBuilder sb = new StringBuilder("sm2");
76 sb.append(one);
77 for (String arg : args) {
78 sb.append(arg);
79 }
80 return sb.toString();
81 }
82
83 enum MethodKind {
84 M1, SM1, M2, SM2;
85 }
86
87 @Reflect
88 String fArray(String[] array, MethodKind m) {
89 return switch (m) {
90 case M1 -> m1(array);
91 case SM1 -> sm1(array);
92 case M2 -> m2("first", array);
93 case SM2 -> sm2("first", array);
94 };
95 }
96
97 @Test
98 public void testArray() {
99 CoreOp.FuncOp f = getFuncOp("fArray");
100 f = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
101
102 invokes(f).forEach(iop -> {
103 Assertions.assertFalse(iop.isVarArgs());
104 Assertions.assertNull(iop.varArgOperands());
105 });
106
107 String[] array = new String[]{"second", "third"};
108 for (MethodKind mk : MethodKind.values()) {
109 Assertions.assertEquals(
110 fArray(array, mk), Interpreter.invoke(MethodHandles.lookup(), f, this, array, mk)
111 );
112 }
113 }
114
115 @Reflect
116 String fEmpty(MethodKind m) {
117 return switch (m) {
118 case M1 -> m1();
119 case SM1 -> sm1();
120 case M2 -> m2("first");
121 case SM2 -> sm2("first");
122 };
123 }
124
125 @Test
126 public void testEmpty() {
127 CoreOp.FuncOp f = getFuncOp("fEmpty");
128 f = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
129
130 invokes(f).forEach(iop -> {
131 Assertions.assertTrue(iop.isVarArgs());
132 Assertions.assertTrue(iop.varArgOperands().isEmpty());
133 });
134
135 String[] array = new String[]{"second", "third"};
136 for (MethodKind mk : MethodKind.values()) {
137 Assertions.assertEquals(
138 fEmpty(mk), Interpreter.invoke(MethodHandles.lookup(), f, this, mk)
139 );
140 }
141 }
142
143 @Reflect
144 String fOne(String one, MethodKind m) {
145 return switch (m) {
146 case M1 -> m1(one);
147 case SM1 -> sm1(one);
148 case M2 -> m2("first", one);
149 case SM2 -> sm2("first", one);
150 };
151 }
152
153 @Test
154 public void testOne() {
155 CoreOp.FuncOp f = getFuncOp("fOne");
156 f = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
157
158 invokes(f).forEach(iop -> {
159 Assertions.assertTrue(iop.isVarArgs());
160 Assertions.assertEquals(1, iop.varArgOperands().size());
161 });
162
163 for (MethodKind mk : MethodKind.values()) {
164 Assertions.assertEquals(
165 fOne("one", mk), Interpreter.invoke(MethodHandles.lookup(), f, this, "one", mk)
166 );
167 }
168 }
169
170 @Reflect
171 String fMany(String one, String two, MethodKind m) {
172 return switch (m) {
173 case M1 -> m1(one, two);
174 case SM1 -> sm1(one, two);
175 case M2 -> m2("first", one, two);
176 case SM2 -> sm2("first", one, two);
177 };
178 }
179
180 @Test
181 public void testMany() {
182 CoreOp.FuncOp f = getFuncOp("fMany");
183 f = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
184
185 invokes(f).forEach(iop -> {
186 Assertions.assertTrue(iop.isVarArgs());
187 Assertions.assertEquals(2, iop.varArgOperands().size());
188 });
189
190 for (MethodKind mk : MethodKind.values()) {
191 Assertions.assertEquals(
192 fMany("one", "two", mk), Interpreter.invoke(MethodHandles.lookup(), f, this, "one", "two", mk)
193 );
194 }
195 }
196
197 static Stream<JavaOp.InvokeOp> invokes(CoreOp.FuncOp f) {
198 return f.elements().mapMulti((ce, c) -> {
199 if (ce instanceof JavaOp.InvokeOp iop &&
200 iop.invokeDescriptor().refType().equals(JavaType.type(TestVarArgsInvoke.class))) {
201 c.accept(iop);
202 }
203 });
204 }
205
206 static CoreOp.FuncOp getFuncOp(String name) {
207 Optional<Method> om = Stream.of(TestVarArgsInvoke.class.getDeclaredMethods())
208 .filter(m -> m.getName().equals(name))
209 .findFirst();
210
211 Method m = om.get();
212 return Op.ofMethod(m).get();
213 }
214
215 }