< prev index next >

hotspot/test/runtime/valhalla/valuetypes/MVTCombo.java

Print this page




  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);


< prev index next >