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