1 /*
  2  * Copyright (c) 2023, 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 value class MyValue1 {
 25     int x = 42;
 26 
 27     void verify() {
 28         if (x != 42) {
 29             throw new RuntimeException("Verification failed");
 30         }
 31     }
 32 }
 33 
 34 value class MyValue2 {
 35     int x = 42;
 36 
 37     void verify() {
 38         if (x != 42) {
 39             throw new RuntimeException("Verification failed");
 40         }
 41     }
 42 }
 43 
 44 value class MyValue3 {
 45     int x = 42;
 46 
 47     void verify() {
 48         if (x != 42) {
 49             throw new RuntimeException("Verification failed");
 50         }
 51     }
 52 }
 53 
 54 value class MyValue4 {
 55     int x = 42;
 56 
 57     public void verify() {
 58         if (x != 42) {
 59             throw new RuntimeException("Verification failed");
 60         }
 61     }
 62 
 63     static MyValue4 make() {
 64         return new MyValue4();
 65     }
 66 }
 67 
 68 interface Verifiable {
 69     public void verify();
 70 }
 71 
 72 value class MyValue5 implements Verifiable {
 73     int x = 42;
 74 
 75     @Override
 76     public void verify() {
 77         if (x != 42) {
 78             throw new RuntimeException("Verification failed");
 79         }
 80     }
 81 
 82     static MyValue5 make() {
 83         return new MyValue5();
 84     }
 85 }
 86 
 87 value class MyValue6 implements Verifiable {
 88     int x = 42;
 89 
 90     @Override
 91     public void verify() {
 92         if (x != 42) {
 93             throw new RuntimeException("Verification failed");
 94         }
 95     }
 96 
 97     static MyValue6 make() {
 98         return new MyValue6();
 99     }
100 }
101 
102 value class MyValue7 {
103     int x = 42;
104 
105     void verify() {
106         if (x != 42) {
107             throw new RuntimeException("Verification failed");
108         }
109     }
110 }
111 
112 class A {
113     public MyValue1 method(MyValue1 arg) {
114         arg.verify();
115         return arg;
116     }
117 }
118 
119 class B extends A {
120     @Override
121     public MyValue1 method(MyValue1 arg) {
122         arg.verify();
123         return arg;
124     }
125 }
126 
127 class C extends B {
128     @Override
129     public MyValue1 method(MyValue1 arg) {
130         arg.verify();
131         return arg;
132     }
133 }
134 
135 interface I1 {
136     public MyValue2 method(MyValue2 arg);
137 }
138 
139 interface I2 extends I1 {
140     public MyValue2 method(MyValue2 arg);
141 }
142 
143 interface I3 {
144     public MyValue2 method(MyValue2 arg);
145 }
146 
147 interface I4 extends I3 {
148     public MyValue2 method(MyValue2 arg);
149 }
150 
151 
152 class D implements I2 {
153     @Override
154     public MyValue2 method(MyValue2 arg) {
155         arg.verify();
156         return arg;
157     }
158 }
159 
160 class E implements I4 {
161     @Override
162     public MyValue2 method(MyValue2 arg) {
163         arg.verify();
164         return arg;
165     }
166 }
167 
168 
169 class F implements I2, I4 {
170     @Override
171     public MyValue2 method(MyValue2 arg) {
172         arg.verify();
173         return arg;
174     }
175 }
176 
177 class G implements I2, I4 {
178     @Override
179     public MyValue2 method(MyValue2 arg) {
180         arg.verify();
181         return arg;
182     }
183 }
184 
185 interface I5 {
186     public MyValue3 method(MyValue3 arg);
187 }
188 
189 class H implements I5 {
190     @Override
191     public MyValue3 method(MyValue3 arg) {
192         arg.verify();
193         return arg;
194     }
195 }
196 
197 class J {
198     public MyValue3 method(MyValue3 arg) {
199         arg.verify();
200         return arg;
201     }
202 }
203 
204 class K extends J {
205     @Override
206     public MyValue3 method(MyValue3 arg) {
207         arg.verify();
208         return arg;
209     }
210 }
211 
212 class L extends K implements I5 {
213     @Override
214     public MyValue3 method(MyValue3 arg) {
215         arg.verify();
216         return arg;
217     }
218 }
219 
220 class M {
221     int val = 0;
222 
223     public MyValue4 method(boolean warmup) {
224         if (warmup) {
225             return null;
226         } else {
227             MyValue4 res = MyValue4.make();
228             // Do something here to "corrupt" registers
229             for (int i = 0; i < 10; ++i) {
230                 val++;
231             }
232             return res;
233         }
234     }
235 }
236 
237 class N {
238     public MyValue5 method(boolean warmup) {
239         if (warmup) {
240             return null;
241         } else {
242             return MyValue5.make();
243         }
244     }
245 }
246 
247 class O {
248     public MyValue6 method(boolean warmup) {
249         if (warmup) {
250             return null;
251         } else {
252             return MyValue6.make();
253         }
254     }
255 }
256 
257 interface I6 {
258     default MyValue7 method(MyValue7 arg) {
259         return null;
260     }
261 }
262 
263 class P implements I6 {
264     @Override
265     public MyValue7 method(MyValue7 arg) {
266         arg.verify();
267         return arg;
268     }
269 }
270 
271 class Q {
272     MyValue7 method(MyValue7 arg) {
273         arg.verify();
274         return arg;
275     }
276 }
277 
278 class R extends Q {
279     @Override
280     MyValue7 method(MyValue7 arg) {
281         arg.verify();
282         return arg;
283     }
284 }
285 
286 class S extends R implements I6 {
287     @Override
288     public MyValue7 method(MyValue7 arg) {
289         arg.verify();
290         return arg;
291     }
292 }
293 
294 class TestMismatchHandlingHelper {
295     // * = has preload attribute for MyValue*
296 
297     // With C <: B* <: A
298     public static void test1(A a1, A a2, A a3, A a4, A a5, B b1, B b2, C c) {
299         // Non-scalarized virtual call site, mismatching on B
300         a1.method(new MyValue1()).verify();
301         a2.method(new MyValue1()).verify();
302         a3.method(new MyValue1()).verify();
303         a4.method(new MyValue1()).verify();
304         a5.method(new MyValue1()).verify();
305         // Scalarized virtual call sites, mismatching on C
306         b1.method(new MyValue1()).verify();
307         b2.method(new MyValue1()).verify();
308         c.method(new MyValue1()).verify();
309     }
310 
311     // D  <: I2  <: I1
312     // E* <: I4* <: I3*
313     // Loaded later, combine both hierachies and introduce a mismatch:
314     // F  <: I2, I4*
315     // G* <: I2, I4*
316     public static void test2(I1 i11, I1 i12, I1 i13, I1 i14, I1 i15, I1 i16, I2 i21, I2 i22, I2 i23, I2 i24, I2 i25, I2 i26, I3 i31, I3 i32, I3 i33, I3 i34, I3 i35, I3 i36, I4 i41, I4 i42, I4 i43, I4 i44, I4 i45, I4 i46, D d, E e) {
317         // Non-scalarized virtual call sites, mismatching on E
318         i11.method(new MyValue2()).verify();
319         i12.method(new MyValue2()).verify();
320         i13.method(new MyValue2()).verify();
321         i14.method(new MyValue2()).verify();
322         i15.method(new MyValue2()).verify();
323         i16.method(new MyValue2()).verify();
324         i21.method(new MyValue2()).verify();
325         i22.method(new MyValue2()).verify();
326         i23.method(new MyValue2()).verify();
327         i24.method(new MyValue2()).verify();
328         i25.method(new MyValue2()).verify();
329         i26.method(new MyValue2()).verify();
330         d.method(new MyValue2()).verify();
331         // Scalarized virtual call sites, mismatching on D
332         i31.method(new MyValue2()).verify();
333         i32.method(new MyValue2()).verify();
334         i33.method(new MyValue2()).verify();
335         i34.method(new MyValue2()).verify();
336         i35.method(new MyValue2()).verify();
337         i36.method(new MyValue2()).verify();
338         i41.method(new MyValue2()).verify();
339         i42.method(new MyValue2()).verify();
340         i43.method(new MyValue2()).verify();
341         i44.method(new MyValue2()).verify();
342         i45.method(new MyValue2()).verify();
343         i46.method(new MyValue2()).verify();
344         e.method(new MyValue2()).verify();
345     }
346 
347     // H  <: I5
348     // K* <: J*
349     // Loaded later, combines both hierachies and introduces a mismatch:
350     // L* <: K*, I5
351     public static void test3(I5 i51, I5 i52, I5 i53, J j1, J j2, J j3, J j4, J j5, H h, K k) {
352         // Non-scalarized virtual call sites, mismatching on L
353         i51.method(new MyValue3()).verify();
354         i52.method(new MyValue3()).verify();
355         i53.method(new MyValue3()).verify();
356         h.method(new MyValue3()).verify();
357         // Scalarized virtual call sites
358         j1.method(new MyValue3()).verify();
359         j2.method(new MyValue3()).verify();
360         j3.method(new MyValue3()).verify();
361         j4.method(new MyValue3()).verify();
362         j5.method(new MyValue3()).verify();
363         k.method(new MyValue3()).verify();
364     }
365 
366     // Test that a C1 compiled method returns in scalarized form if the method holder class M
367     // is loaded but the value class return type is not due to a missing preload attribute.
368     public static void test4(M m, boolean warmup) {
369         if (warmup) {
370             m.method(warmup);
371         } else {
372             if (m.method(warmup).x != 42) {
373                 throw new RuntimeException("Verification failed");
374             }
375         }
376     }
377 
378     // Test that C1 correctly handles scalarized returns at calls if the method holder class N
379     // is loaded but the value class return type is not due to a missing preload attribute.
380     public static void test5(N n, boolean warmup) {
381         Verifiable res = n.method(warmup);
382         if (!warmup) {
383             res.verify();
384         }
385     }
386 
387     // Test direct calls
388     public static void test6(F f, G g, L l) {
389         f.method(new MyValue2());
390         g.method(new MyValue2());
391         l.method(new MyValue3());
392     }
393 
394     // Test scalarized return from C2 compiled callee to C2 compiled caller with an unloaded
395     // return type at caller compile time due to a missing preload attribute.
396     public static Verifiable test7(O o, boolean warmup) {
397         return o.method(warmup);
398     }
399 
400     public static void test7TriggerCalleeCompilation(O o) {
401         o.method(true);
402         o.method(false).verify();
403     }
404 
405     // Same as test3 but with default method in interface and package private methods
406     // P  <: I6
407     // R* <: Q*
408     // Loaded later, combines both hierachies and introduces a mismatch:
409     // S* <: R*, I6
410     public static void test8(I6 i61, I6 i62, I6 i63, Q q1, Q q2, Q q3, Q q4, Q q5, P p, R r) {
411         // Non-scalarized virtual call sites, mismatching on S
412         i61.method(new MyValue7()).verify();
413         i62.method(new MyValue7()).verify();
414         i63.method(new MyValue7()).verify();
415         p.method(new MyValue7()).verify();
416         // Scalarized virtual call sites
417         q1.method(new MyValue7()).verify();
418         q2.method(new MyValue7()).verify();
419         q3.method(new MyValue7()).verify();
420         q4.method(new MyValue7()).verify();
421         q5.method(new MyValue7()).verify();
422         r.method(new MyValue7()).verify();
423     }
424 }