1 /*
  2  * Copyright (c) 2019, 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 package runtime.valhalla.inlinetypes;
 26 
 27 import java.lang.reflect.*;
 28 import static jdk.test.lib.Asserts.*;
 29 
 30 import jdk.internal.vm.annotation.ImplicitlyConstructible;
 31 import jdk.internal.vm.annotation.LooselyConsistentValue;
 32 import jdk.internal.vm.annotation.NullRestricted;
 33 
 34 /*
 35  * @test VarArgsArray
 36  * @summary Test if JVM API using varargs work with inline type arrays
 37  * @modules java.base/jdk.internal.value
 38  * @library /test/lib
 39  * @modules java.base/jdk.internal.vm.annotation
 40  * @enablePreview
 41  * @compile VarArgsArray.java
 42  * @run main/othervm runtime.valhalla.inlinetypes.VarArgsArray
 43  */
 44 
 45 @ImplicitlyConstructible
 46 @LooselyConsistentValue
 47 value class IntValue {
 48     int val;
 49     public IntValue()       { this(0); }
 50     public IntValue(int v)  { val = v; }
 51     public int getInt()     { return val; }
 52 }
 53 
 54 
 55 class NewInstanceFromConstructor {
 56 
 57     int value;
 58     static int consCalls = 0;
 59 
 60     public NewInstanceFromConstructor() {
 61         this(0);
 62     }
 63 
 64     public NewInstanceFromConstructor(int v) {
 65         value = v;
 66         consCalls++;
 67     }
 68 
 69     public NewInstanceFromConstructor(IntValue v) {
 70         this(v.getInt());
 71     }
 72 
 73     public NewInstanceFromConstructor(IntValue v1,
 74                                       IntValue v2) {
 75         this(v1.getInt() + v2.getInt());
 76     }
 77 
 78     public NewInstanceFromConstructor(IntValue v1,
 79                                       String s) {
 80         this(v1);
 81         throw new RuntimeException(s);
 82     }
 83 
 84     public int getValue() { return value; }
 85 
 86     public static int getConsCalls() { return consCalls; }
 87 }
 88 
 89 public class VarArgsArray {
 90 
 91     static final int TOKEN_VALUE = 4711;
 92 
 93     int methodACnt = 0;
 94     int methodBCnt = 0;
 95     int methodCCnt = 0;
 96 
 97     public VarArgsArray() {
 98     }
 99 
100     public void test() throws Throwable {
101         // test publicly accessable API in the VM...given an inline type array
102         testJvmInvokeMethod();
103         testJvmNewInstanceFromConstructor();
104     }
105 
106     public void testJvmInvokeMethod() throws Throwable {
107         MyInt[] array0 = new MyInt[0];
108         MyInt[] array1 = new MyInt[] { new MyInt(TOKEN_VALUE) };
109         MyInt[] array2 = new MyInt[] { new MyInt(TOKEN_VALUE), new MyInt(TOKEN_VALUE) };
110 
111         Method methodARef = getClass().getDeclaredMethod("methodA", MyInt.class);
112         Method methodBRef = getClass().getDeclaredMethod("methodB", MyInt.class, MyInt.class);
113         Method methodCRef = getClass().getDeclaredMethod("methodC", MyInt.class, String.class);
114 
115         // Positive tests...
116         methodARef.invoke(this, (Object[])array1);
117         assertWithMsg(methodACnt == 1, "methodA did not invoke");
118 
119         methodARef.invoke(this, array1[0]);
120         assertWithMsg(methodACnt == 2, "methodA did not invoke");
121 
122         methodBRef.invoke(this, (Object[]) array2);
123         assertWithMsg(methodBCnt == 1, "methodB did not invoke");
124 
125         methodBRef.invoke(this, array2[0], array2[1]);
126         assertWithMsg(methodBCnt == 2, "methodB did not invoke");
127 
128         // Negative tests...
129         int argExCnt = 0;
130         try {
131             methodARef.invoke(this, (Object[]) array0);
132             throw new RuntimeException("Expected fail");
133         } catch (IllegalArgumentException argEx) { argExCnt++; }
134         try {
135             methodARef.invoke(this, (Object[]) array2);
136             throw new RuntimeException("Expected fail");
137         } catch (IllegalArgumentException argEx) { argExCnt++; }
138         try {
139             methodCRef.invoke(this, (Object[]) array2);
140             throw new RuntimeException("Expected fail");
141         } catch (IllegalArgumentException argEx) { argExCnt++; }
142         assertWithMsg(argExCnt == 3, "Did not see the correct number of exceptions");
143         assertWithMsg(methodACnt == 2, "methodA bad invoke count");
144         assertWithMsg(methodBCnt == 2, "methodB bad invoke count");
145         assertWithMsg(methodCCnt == 0, "methodC bad invoke count");
146     }
147 
148     public void testJvmNewInstanceFromConstructor() throws Throwable {
149         // Inner classes use outer in param list, so these won't exercise inline type array
150         Class tc = NewInstanceFromConstructor.class;
151         Class pt = IntValue.class;
152         Constructor consARef = tc.getConstructor(pt);
153         Constructor consBRef = tc.getConstructor(pt, pt);
154         Constructor consCRef = tc.getConstructor(pt, String.class);
155         IntValue[] array0 = new IntValue[0];
156         IntValue[] array1 = new IntValue[] { new IntValue(TOKEN_VALUE) };
157         IntValue[] array2 = new IntValue[] { new IntValue(TOKEN_VALUE),
158                                              new IntValue(TOKEN_VALUE) };
159 
160         // Positive tests...
161         consARef.newInstance((Object[])array1);
162         consARef.newInstance(array1[0]);
163         NewInstanceFromConstructor test = (NewInstanceFromConstructor)
164             consBRef.newInstance((Object[])array2);
165         assertWithMsg(test.getValue() == (2 * TOKEN_VALUE), "Param corrrupt");
166         consBRef.newInstance(array2[0], array2[1]);
167         assertWithMsg(NewInstanceFromConstructor.getConsCalls() == 4, "Constructor did not invoke");
168 
169         // Negative tests...
170         int argExCnt = 0;
171         try {
172             consARef.newInstance((Object[])array0);
173             throw new RuntimeException("Expected fail");
174         } catch (IllegalArgumentException argEx) { argExCnt++; }
175         try {
176             consARef.newInstance((Object[])array2);
177             throw new RuntimeException("Expected fail");
178         } catch (IllegalArgumentException argEx) { argExCnt++; }
179         try {
180             consCRef.newInstance((Object[])array2);
181             throw new RuntimeException("Expected fail");
182         } catch (IllegalArgumentException argEx) { argExCnt++; }
183         assertWithMsg(argExCnt == 3, "Did not see the correct number of exceptions");
184         assertWithMsg(NewInstanceFromConstructor.getConsCalls() == 4, "Constructor should have been invoked");
185     }
186 
187     public void methodA(MyInt a) {
188         assertWithMsg(a.value == TOKEN_VALUE, "Bad arg");
189         methodACnt++;
190     }
191 
192     public void methodB(MyInt a, MyInt b) {
193         assertWithMsg(a.value == TOKEN_VALUE, "Bad arg");
194         assertWithMsg(b.value == TOKEN_VALUE, "Bad arg");
195         methodBCnt++;
196     }
197 
198     public void methodC(MyInt a, String b) {
199         assertWithMsg(a.value == TOKEN_VALUE, "Bad arg");
200         methodCCnt++;
201     }
202 
203     static void assertWithMsg(boolean expr, String msg) throws RuntimeException {
204         assertTrue(expr, msg);
205     }
206 
207     public static void main(String[] args) throws Throwable {
208         new VarArgsArray().test();
209     }
210 
211     @ImplicitlyConstructible
212     @LooselyConsistentValue
213     value class MyInt {
214         int value;
215         public MyInt() { this(0); }
216         public MyInt(int v) { this.value = v; }
217     }
218 
219 
220 }