14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package runtime.valhalla.valuetypes;
26
27 import javax.tools.JavaFileObject;
28
29 import jdk.test.lib.combo.ComboInstance;
30 import jdk.test.lib.combo.ComboParameter;
31 import jdk.test.lib.combo.ComboTask.Result;
32 import jdk.test.lib.combo.ComboTestHelper;
33 import jdk.test.lib.combo.ComboTestHelper.ArrayDimensionKind;
34 import jdk.experimental.value.ValueType;
35
36 import java.io.File;
37 import java.io.FileInputStream;
38 import java.lang.invoke.MethodHandle;
39 import java.lang.invoke.MethodHandles;
40 import java.lang.invoke.MethodType;
41 import static java.lang.invoke.MethodType.methodType;
42 import java.lang.reflect.Field;
43 import java.lang.reflect.Modifier;
44 import java.net.URL;
45 import java.net.URLClassLoader;
46 import java.util.stream.Stream;
47
48 /**
49 * Test combinations of value type field layouts.
50 *
51 * Testing all permutations of all 8 primitive types and a reference type is
52 * prohibitive both in terms of resource usage on testing infrastructure, and
53 * development time. Sanity or "check-in" level testing should be in the order
54 * of seconds in terms of wall-clock execution time.
55 *
56 * ### Combinations vs Permutations
57 *
58 * For a given number of fields, or "set of cardinality 'K'" ("arity" in code
59 * here), of a set of "N" types ("BasicType"), the number of test cases can be
60 * expressed as:
180 String sep;
181
182 Snippet(String snippetStr, String sep) {
183 this.snippetStr = snippetStr;
184 this.sep = sep;
185 }
186
187 String expand(int arity) {
188 StringBuilder buf = new StringBuilder();
189 String tempSep = "";
190 for (int i = 0 ; i < arity ; i++) {
191 buf.append(tempSep);
192 buf.append(snippetStr.replaceAll("#IDX", String.valueOf(i)));
193 tempSep = sep;
194 }
195 return buf.toString();
196 }
197 }
198
199 public static final String VCC_TEMPLATE =
200 "@jvm.internal.value.ValueCapableClass\n" +
201 "public final class Test {\n\n" +
202 " // Declare fields...\n" +
203 " #{ARITY.FIELD_DECL}\n" +
204 " // Private Constructor...\n" +
205 " private Test(#{ARITY.CONSTR_FORMALS}) {\n" +
206 " #{ARITY.FIELD_ASSIGN}\n" +
207 " }\n" +
208 " public boolean equals(Object o) {\n" +
209 " Test that = (Test) o;\n" +
210 " #{ARITY.FIELD_EQUALS}\n" +
211 " return true;\n" +
212 " }\n" +
213 " // Public factory method\n" +
214 " public static Test create(#{ARITY.CONSTR_FORMALS}) {\n" +
215 " return new Test(#{ARITY.CONSTR_ACTUALS});\n" +
216 " }\n" +
217 " // Public indexed test case factory method\n" +
218 " public static Test createIndexed(int INDEX) {\n" +
219 " return new Test(#{ARITY.CONSTR_ACTUALS_INDEXED});\n" +
220 " }\n" +
281 }
282
283 /*
284 The way the 'combo' package works, it produces combinations or permutations
285 for each dimension, so for arity we don't care for basicTypes[arity...maxArity]
286 */
287 boolean redundantFilter() {
288 BasicType lastArityType = basicTypes[arity.arity - 1];
289 for (int i = arity.arity ; i < arity.maxArity ; i++) {
290 if (basicTypes[i] != lastArityType) {
291 return false;
292 }
293 }
294 return true;
295 }
296
297 @Override
298 public void doWork() throws Throwable {
299 Result<Iterable<? extends JavaFileObject>> result = newCompilationTask()
300 .withSourceFromTemplate(VCC_TEMPLATE)
301 .generate();
302 //System.out.println("COMP: " + result.compilationInfo()); // Print the generated source
303 if (result.hasErrors()) {
304 fail("ERROR " + result.compilationInfo());
305 }
306 JavaFileObject jfo = result.get().iterator().next(); // Blindly assume one
307 String url = jfo.toUri().toURL().toString();
308 url = url.substring(0, url.length() - jfo.getName().length());
309 Class<?> clazz = new URLClassLoader(new URL[] { new URL(url) }).loadClass("Test");
310 try {
311 doTestMvtClasses(clazz);
312 doTestSingleInstance(clazz);
313 doTestArray(clazz);
314 } catch (Throwable ex) {
315 throw new AssertionError("ERROR: " + result.compilationInfo(), ex);
316 }
317 }
318
319 protected void doTestMvtClasses(Class<?> testSubject) throws Throwable {
320 if (!ValueType.classHasValueType(testSubject)) {
321 throw new IllegalArgumentException("Not a VCC: " + testSubject);
322 }
323 ValueType<?> vt = ValueType.forClass(testSubject);
324 Class<?> boxClass = vt.boxClass();
325 Class<?> sourceClass = vt.sourceClass();
326 Class<?> vtClass = vt.valueClass();
327 Class<?> arrayClass = vt.arrayValueClass();
328 Class<?> mArrayClass = vt.arrayValueClass(4);
329 if (boxClass != testSubject) {
330 throw new RuntimeException("Box class != VCC");
331 }
332 if (sourceClass != testSubject) {
333 throw new RuntimeException("Source class != VCC");
334 }
335 if (vt.toString() == null) {
336 throw new RuntimeException("No toString() return");
337 }
338 }
339
340 protected void doTestSingleInstance(Class<?> testSubject) throws Throwable {
341 ValueType<?> vt = ValueType.forClass(testSubject);
342 Object obj = MethodHandles.filterReturnValue(vt.defaultValueConstant(), vt.box()).invoke();
343 obj = MethodHandles.filterReturnValue(vt.unbox(), vt.box()).invoke(obj);
344 int hashCode = (int) MethodHandles.filterReturnValue(vt.defaultValueConstant(), vt.substitutabilityHashCode()).invoke();
345
346 //test(default(), default())
347 MethodHandle test0 = MethodHandles.collectArguments(vt.substitutabilityTest(), 0, vt.defaultValueConstant());
348 boolean isEqual = (boolean) MethodHandles.collectArguments(test0, 0, vt.defaultValueConstant()).invoke();
349 if (!isEqual) {
350 throw new RuntimeException("test(default(), default()) failed");
351 }
352 }
353
354 protected void doTestArray(Class<?> testSubject) throws Throwable {
355 ValueType<?> vt = ValueType.forClass(testSubject);
356 MethodHandle arrayGetter = vt.arrayGetter();
357 MethodHandle arraySetter = vt.arraySetter();
358 MethodHandle unbox = vt.unbox();
359 MethodHandle box = vt.box();
360 int testArrayLen = 7;
361 Object array = vt.newArray().invoke(testArrayLen);
362 for (int i = 0; i < testArrayLen; i++) {
363 MethodHandle equalsDefault0 = MethodHandles.collectArguments(vt.substitutabilityTest(), 0, vt.defaultValueConstant());
364 boolean isEqual = (boolean) MethodHandles.collectArguments(equalsDefault0, 0, arrayGetter).invoke(array, i);
365 if (!isEqual) {
366 System.out.println("PROBLEM:");
367 printFieldValues(MethodHandles.filterReturnValue(vt.defaultValueConstant(), box));
368 System.out.println("VERSUS value from array:");
369 printFieldValues(MethodHandles.filterReturnValue(arrayGetter, box).invoke(array, i));
370 throw new IllegalStateException("Failed equality test for class: " + vt.sourceClass().getName() + " at index: " + i);
371 }
372 }
373
374 // populate the last element with some values...
375 int testIndex = testArrayLen - 1;
376 /*
377 Do the following in MHs...
378
379 Object testObj = Test.createIndexed(testIndex);
380 array[testIndex] = unbox(testObj);
381 if (!testObj.equals(array[testIndex])) throw...
382 */
383 MethodHandle createIndexed = MethodHandles.privateLookupIn(testSubject, mhLookup)
384 .findStatic(testSubject, "createIndexed", methodType(testSubject, Integer.TYPE));
385 Object testObj = createIndexed.invoke(testIndex);
386 arraySetter.invoke(array, testIndex, testObj);
387 Object testElem = MethodHandles.filterReturnValue(arrayGetter, box).invoke(array, testIndex);
388 if (!testObj.equals(testElem)) {
389 System.out.println("PROBLEM:");
390 printFieldValues(testObj);
|
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package runtime.valhalla.valuetypes;
26
27 import javax.tools.JavaFileObject;
28
29 import jdk.test.lib.combo.ComboInstance;
30 import jdk.test.lib.combo.ComboParameter;
31 import jdk.test.lib.combo.ComboTask.Result;
32 import jdk.test.lib.combo.ComboTestHelper;
33 import jdk.test.lib.combo.ComboTestHelper.ArrayDimensionKind;
34 import jdk.incubator.mvt.ValueType;
35
36 import java.lang.invoke.MethodHandle;
37 import java.lang.invoke.MethodHandles;
38 import static java.lang.invoke.MethodType.methodType;
39 import java.lang.reflect.Field;
40 import java.lang.reflect.Modifier;
41 import java.net.URL;
42 import java.net.URLClassLoader;
43 import java.util.stream.Stream;
44
45 /**
46 * Test combinations of value type field layouts.
47 *
48 * Testing all permutations of all 8 primitive types and a reference type is
49 * prohibitive both in terms of resource usage on testing infrastructure, and
50 * development time. Sanity or "check-in" level testing should be in the order
51 * of seconds in terms of wall-clock execution time.
52 *
53 * ### Combinations vs Permutations
54 *
55 * For a given number of fields, or "set of cardinality 'K'" ("arity" in code
56 * here), of a set of "N" types ("BasicType"), the number of test cases can be
57 * expressed as:
177 String sep;
178
179 Snippet(String snippetStr, String sep) {
180 this.snippetStr = snippetStr;
181 this.sep = sep;
182 }
183
184 String expand(int arity) {
185 StringBuilder buf = new StringBuilder();
186 String tempSep = "";
187 for (int i = 0 ; i < arity ; i++) {
188 buf.append(tempSep);
189 buf.append(snippetStr.replaceAll("#IDX", String.valueOf(i)));
190 tempSep = sep;
191 }
192 return buf.toString();
193 }
194 }
195
196 public static final String VCC_TEMPLATE =
197 "@jdk.incubator.mvt.ValueCapableClass\n" +
198 "public final class Test {\n\n" +
199 " // Declare fields...\n" +
200 " #{ARITY.FIELD_DECL}\n" +
201 " // Private Constructor...\n" +
202 " private Test(#{ARITY.CONSTR_FORMALS}) {\n" +
203 " #{ARITY.FIELD_ASSIGN}\n" +
204 " }\n" +
205 " public boolean equals(Object o) {\n" +
206 " Test that = (Test) o;\n" +
207 " #{ARITY.FIELD_EQUALS}\n" +
208 " return true;\n" +
209 " }\n" +
210 " // Public factory method\n" +
211 " public static Test create(#{ARITY.CONSTR_FORMALS}) {\n" +
212 " return new Test(#{ARITY.CONSTR_ACTUALS});\n" +
213 " }\n" +
214 " // Public indexed test case factory method\n" +
215 " public static Test createIndexed(int INDEX) {\n" +
216 " return new Test(#{ARITY.CONSTR_ACTUALS_INDEXED});\n" +
217 " }\n" +
278 }
279
280 /*
281 The way the 'combo' package works, it produces combinations or permutations
282 for each dimension, so for arity we don't care for basicTypes[arity...maxArity]
283 */
284 boolean redundantFilter() {
285 BasicType lastArityType = basicTypes[arity.arity - 1];
286 for (int i = arity.arity ; i < arity.maxArity ; i++) {
287 if (basicTypes[i] != lastArityType) {
288 return false;
289 }
290 }
291 return true;
292 }
293
294 @Override
295 public void doWork() throws Throwable {
296 Result<Iterable<? extends JavaFileObject>> result = newCompilationTask()
297 .withSourceFromTemplate(VCC_TEMPLATE)
298 .withOption("--add-modules=jdk.incubator.mvt")
299 .generate();
300 //System.out.println("COMP: " + result.compilationInfo()); // Print the generated source
301 if (result.hasErrors()) {
302 fail("ERROR " + result.compilationInfo());
303 }
304 JavaFileObject jfo = result.get().iterator().next(); // Blindly assume one
305 String url = jfo.toUri().toURL().toString();
306 url = url.substring(0, url.length() - jfo.getName().length());
307 Class<?> clazz = new URLClassLoader(new URL[] { new URL(url) }).loadClass("Test");
308 try {
309 doTestMvtClasses(clazz);
310 doTestSingleInstance(clazz);
311 doTestArray(clazz);
312 } catch (Throwable ex) {
313 throw new AssertionError("ERROR: " + result.compilationInfo(), ex);
314 }
315 }
316
317 protected void doTestMvtClasses(Class<?> testSubject) throws Throwable {
318 if (!ValueType.classHasValueType(testSubject)) {
319 throw new IllegalArgumentException("Not a VCC: " + testSubject);
320 }
321 ValueType<?> vt = ValueType.forClass(testSubject);
322 Class<?> boxClass = vt.boxClass();
323 Class<?> vtClass = vt.valueClass();
324 Class<?> arrayClass = vt.arrayValueClass();
325 Class<?> mArrayClass = vt.arrayValueClass(4);
326 if (boxClass != testSubject) {
327 throw new RuntimeException("Box class != VCC");
328 }
329 if (vt.toString() == null) {
330 throw new RuntimeException("No toString() return");
331 }
332 }
333
334 protected void doTestSingleInstance(Class<?> testSubject) throws Throwable {
335 ValueType<?> vt = ValueType.forClass(testSubject);
336 Object obj = MethodHandles.filterReturnValue(vt.defaultValueConstant(), vt.box()).invoke();
337 obj = MethodHandles.filterReturnValue(vt.unbox(), vt.box()).invoke(obj);
338 int hashCode = (int) MethodHandles.filterReturnValue(vt.defaultValueConstant(), vt.substitutabilityHashCode()).invoke();
339
340 //test(default(), default())
341 MethodHandle test0 = MethodHandles.collectArguments(vt.substitutabilityTest(), 0, vt.defaultValueConstant());
342 boolean isEqual = (boolean) MethodHandles.collectArguments(test0, 0, vt.defaultValueConstant()).invoke();
343 if (!isEqual) {
344 throw new RuntimeException("test(default(), default()) failed");
345 }
346 }
347
348 protected void doTestArray(Class<?> testSubject) throws Throwable {
349 ValueType<?> vt = ValueType.forClass(testSubject);
350 MethodHandle arrayGetter = vt.arrayGetter();
351 MethodHandle arraySetter = vt.arraySetter();
352 MethodHandle unbox = vt.unbox();
353 MethodHandle box = vt.box();
354 int testArrayLen = 7;
355 Object array = vt.newArray().invoke(testArrayLen);
356 for (int i = 0; i < testArrayLen; i++) {
357 MethodHandle equalsDefault0 = MethodHandles.collectArguments(vt.substitutabilityTest(), 0, vt.defaultValueConstant());
358 boolean isEqual = (boolean) MethodHandles.collectArguments(equalsDefault0, 0, arrayGetter).invoke(array, i);
359 if (!isEqual) {
360 System.out.println("PROBLEM:");
361 printFieldValues(MethodHandles.filterReturnValue(vt.defaultValueConstant(), box));
362 System.out.println("VERSUS value from array:");
363 printFieldValues(MethodHandles.filterReturnValue(arrayGetter, box).invoke(array, i));
364 throw new IllegalStateException("Failed equality test for class: " + vt.boxClass().getName() + " at index: " + i);
365 }
366 }
367
368 // populate the last element with some values...
369 int testIndex = testArrayLen - 1;
370 /*
371 Do the following in MHs...
372
373 Object testObj = Test.createIndexed(testIndex);
374 array[testIndex] = unbox(testObj);
375 if (!testObj.equals(array[testIndex])) throw...
376 */
377 MethodHandle createIndexed = MethodHandles.privateLookupIn(testSubject, mhLookup)
378 .findStatic(testSubject, "createIndexed", methodType(testSubject, Integer.TYPE));
379 Object testObj = createIndexed.invoke(testIndex);
380 arraySetter.invoke(array, testIndex, testObj);
381 Object testElem = MethodHandles.filterReturnValue(arrayGetter, box).invoke(array, testIndex);
382 if (!testObj.equals(testElem)) {
383 System.out.println("PROBLEM:");
384 printFieldValues(testObj);
|