1 /*
   2  * Copyright (c) 2017, 2019, 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 package runtime.valhalla.valuetypes;
  25 
  26 import java.io.File;
  27 import java.io.IOException;
  28 import java.io.PrintWriter;
  29 import java.lang.invoke.*;
  30 import java.lang.ref.*;
  31 import java.util.ArrayList;
  32 import java.util.Arrays;
  33 import java.util.List;
  34 import java.util.concurrent.*;
  35 
  36 import static jdk.test.lib.Asserts.*;
  37 
  38 import jdk.experimental.bytecode.MacroCodeBuilder;
  39 import jdk.experimental.bytecode.MacroCodeBuilder.CondKind;
  40 import jdk.experimental.bytecode.TypeTag;
  41 import jdk.test.lib.Platform;
  42 import jdk.test.lib.Utils;
  43 
  44 import jdk.experimental.value.MethodHandleBuilder;
  45 
  46 import javax.tools.*;
  47 
  48 /**
  49  * @test ValueTypesTest
  50  * @summary Test data movement with inline types
  51  * @modules java.base/jdk.experimental.bytecode
  52  *          java.base/jdk.experimental.value
  53  * @library /test/lib
  54  * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator TestValue1.java TestValue2.java TestValue3.java TestValue4.java ValueTypesTest.java
  55  * @run main/othervm -Xint -Xmx128m -XX:-ShowMessageBoxOnError
  56  *                   -XX:+ExplicitGCInvokesConcurrent
  57  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
  58  *                   -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=false
  59  *                   runtime.valhalla.valuetypes.ValueTypesTest
  60  * @run main/othervm -Xcomp -Xmx128m -XX:-ShowMessageBoxOnError
  61  *                   -XX:+ExplicitGCInvokesConcurrent
  62  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
  63  *                   -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=false
  64  *                   runtime.valhalla.valuetypes.ValueTypesTest
  65  * @run main/othervm -Xbatch -Xmx128m -XX:-ShowMessageBoxOnError
  66  *                   -XX:+ExplicitGCInvokesConcurrent
  67  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
  68  *                   -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=false
  69  *                   -XX:ForceNonTearable=*
  70  *                   runtime.valhalla.valuetypes.ValueTypesTest
  71  */
  72 public class ValueTypesTest {
  73 
  74     public static void main(String[] args) {
  75         Class<?> inlineClass = runtime.valhalla.valuetypes.TestValue1.class;
  76         Class<?> testClasses[] = {
  77                 runtime.valhalla.valuetypes.TestValue1.class,
  78                 runtime.valhalla.valuetypes.TestValue2.class,
  79                 runtime.valhalla.valuetypes.TestValue3.class,
  80                 runtime.valhalla.valuetypes.TestValue4.class
  81         };
  82         Class<?> containerClasses[] = {
  83                 runtime.valhalla.valuetypes.ContainerValue1.class,
  84                 runtime.valhalla.valuetypes.ContainerValue2.class,
  85                 runtime.valhalla.valuetypes.ContainerValue3.class,
  86                 runtime.valhalla.valuetypes.ContainerValue4.class
  87         };
  88 
  89         for (int i = 0; i < testClasses.length; i++) {
  90             try {
  91                 testExecutionStackToLocalVariable(testClasses[i]);
  92                 testExecutionStackToFields(testClasses[i], containerClasses[i]);
  93                 // testExecutionStackToValueArray(testClasses[i], containerClasses[i]);
  94             } catch (Throwable t) {
  95                 t.printStackTrace();
  96                 throw new RuntimeException(t);
  97             }
  98         }
  99     }
 100 
 101     static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 102 
 103     static void testExecutionStackToLocalVariable(Class<?> inlineClass) throws Throwable {
 104         String sig = "()Q" + inlineClass.getName() + ";";
 105         final String signature = sig.replace('.', '/');
 106         MethodHandle fromExecStackToLocalVar = MethodHandleBuilder.loadCode(
 107                 LOOKUP,
 108                 "execStackToLocalVar",
 109                 MethodType.methodType(boolean.class),
 110                 CODE -> {
 111                     CODE.invokestatic(System.class, "gc", "()V", false);
 112                     int n = -1;
 113                     while (n < 1024) {
 114                         n++;
 115                         CODE
 116                         .invokestatic(inlineClass, "getInstance", signature, false)
 117                         .astore(n);
 118                         n++;
 119                         CODE
 120                         .invokestatic(inlineClass, "getNonBufferedInstance", signature, false)
 121                         .astore(n);
 122                     }
 123                     CODE.invokestatic(System.class, "gc", "()V", false);
 124                     while (n > 0) {
 125                         CODE
 126                         .aload(n)
 127                         .invokevirtual(inlineClass, "verify", "()Z", false)
 128                         .iconst_1()
 129                         .ifcmp(TypeTag.I, CondKind.NE, "end");
 130                         n--;
 131                     }
 132                     CODE
 133                     .iconst_1()
 134                     .return_(TypeTag.Z)
 135                     .label("end")
 136                     .iconst_0()
 137                     .return_(TypeTag.Z);
 138                 });
 139         boolean result = (boolean) fromExecStackToLocalVar.invokeExact();
 140         System.out.println(result);
 141         assertTrue(result, "Invariant");
 142     }
 143 
 144     static void testExecutionStackToFields(Class<?> inlineClass, Class<?> containerClass) throws Throwable {
 145         final int ITERATIONS = Platform.isDebugBuild() ? 3 : 512;
 146         String sig = "()Q" + inlineClass.getName() + ";";
 147         final String methodSignature = sig.replace('.', '/');
 148         final String fieldQSignature = "Q" + inlineClass.getName().replace('.', '/') + ";";
 149         final String fieldLSignature = "L" + inlineClass.getName().replace('.', '/') + ";";
 150         System.out.println(methodSignature);
 151         MethodHandle fromExecStackToFields = MethodHandleBuilder.loadCode(
 152                 LOOKUP,
 153                 "execStackToFields",
 154                 MethodType.methodType(boolean.class),
 155                 CODE -> {
 156                     CODE
 157                     .invokestatic(System.class, "gc", "()V", false)
 158                     .new_(containerClass)
 159                     .dup()
 160                     .invoke(MacroCodeBuilder.InvocationKind.INVOKESPECIAL, containerClass, "<init>", "()V", false)
 161                     .astore_1()
 162                     .iconst_m1()
 163                     .istore_2()
 164                     .label("loop")
 165                     .iload_2()
 166                     .ldc(ITERATIONS)
 167                     .ifcmp(TypeTag.I, CondKind.EQ, "end")
 168                     .aload_1()
 169                     .invokestatic(inlineClass, "getInstance", methodSignature, false)
 170                     .putfield(containerClass, "nonStaticValueField", fieldQSignature)
 171                     .invokestatic(System.class, "gc", "()V", false)
 172                     .aload_1()
 173                     .getfield(containerClass, "nonStaticValueField", fieldQSignature)
 174                     .invokevirtual(inlineClass, "verify", "()Z", false)
 175                     .iconst_1()
 176                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 177                     .aload_1()
 178                     .invokestatic(inlineClass, "getNonBufferedInstance", methodSignature, false)
 179                     .putfield(containerClass, "nonStaticValueField", fieldQSignature)
 180                     .invokestatic(System.class, "gc", "()V", false)
 181                     .aload_1()
 182                     .getfield(containerClass, "nonStaticValueField", fieldQSignature)
 183                     .invokevirtual(inlineClass, "verify", "()Z", false)
 184                     .iconst_1()
 185                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 186                     .invokestatic(inlineClass, "getInstance", methodSignature, false)
 187                     .putstatic(containerClass, "staticValueField", fieldLSignature)
 188                     .invokestatic(System.class, "gc", "()V", false)
 189                     .getstatic(containerClass, "staticValueField", fieldLSignature)
 190                     .invokevirtual(inlineClass, "verify", "()Z", false)
 191                     .iconst_1()
 192                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 193                     .invokestatic(inlineClass, "getNonBufferedInstance", methodSignature, false)
 194                     .putstatic(containerClass, "staticValueField", fieldLSignature)
 195                     .invokestatic(System.class, "gc", "()V", false)
 196                     .getstatic(containerClass, "staticValueField", fieldLSignature)
 197                     .invokevirtual(inlineClass, "verify", "()Z", false)
 198                     .iconst_1()
 199                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 200                     .iinc(2, 1)
 201                     .goto_("loop")
 202                     .label("end")
 203                     .iconst_1()
 204                     .return_(TypeTag.Z)
 205                     .label("failed")
 206                     .iconst_0()
 207                     .return_(TypeTag.Z);
 208                 });
 209         boolean result = (boolean) fromExecStackToFields.invokeExact();
 210         System.out.println(result);
 211         assertTrue(result, "Invariant");
 212     }
 213 
 214     static void testExecutionStackToValueArray(Class<?> inlineClass, Class<?> containerClass) throws Throwable {
 215         final int ITERATIONS = Platform.isDebugBuild() ? 3 : 100;
 216         String sig = "()Q" + inlineClass.getName() + ";";
 217         final String signature = sig.replace('.', '/');
 218         final String arraySignature = "[L" + inlineClass.getName().replace('.', '/') + ";";
 219         System.out.println(arraySignature);
 220         MethodHandle fromExecStackToValueArray = MethodHandleBuilder.loadCode(
 221                 LOOKUP,
 222                 "execStackToValueArray",
 223                 MethodType.methodType(boolean.class),
 224                 CODE -> {
 225                     CODE
 226                     .invokestatic(System.class, "gc", "()V", false)
 227                     .new_(containerClass)
 228                     .dup()
 229                     .invoke(MacroCodeBuilder.InvocationKind.INVOKESPECIAL, containerClass, "<init>", "()V", false)
 230                     .astore_1()
 231                     .ldc(ITERATIONS * 3)
 232                     .anewarray(inlineClass)
 233                     .astore_2()
 234                     .aload_2()
 235                     .aload_1()
 236                     .swap()
 237                     .putfield(containerClass, "valueArray", arraySignature)
 238                     .iconst_0()
 239                     .istore_3()
 240                     .label("loop1")
 241                     .iload_3()
 242                     .ldc(ITERATIONS)
 243                     .ifcmp(TypeTag.I, CondKind.GE, "end1")
 244                     .aload_2()
 245                     .iload_3()
 246                     .invokestatic(inlineClass, "getInstance", signature, false)
 247                     .aastore()
 248                     .iinc(3, 1)
 249                     .aload_2()
 250                     .iload_3()
 251                     .invokestatic(inlineClass, "getNonBufferedInstance", signature, false)
 252                     .aastore()
 253                     .iinc(3, 1)
 254                     .aload_2()
 255                     .iload_3()
 256                     .defaultvalue(inlineClass)
 257                     .aastore()
 258                     .iinc(3, 1)
 259                     .goto_("loop1")
 260                     .label("end1")
 261                     .invokestatic(System.class, "gc", "()V", false)
 262                     .iconst_0()
 263                     .istore_3()
 264                     .label("loop2")
 265                     .iload_3()
 266                     .ldc(ITERATIONS * 3)
 267                     .ifcmp(TypeTag.I, CondKind.GE, "end2")
 268                     .aload_2()
 269                     .iload_3()
 270                     .aaload()
 271                     .invokevirtual(inlineClass, "verify", "()Z", false)
 272                     .iconst_1()
 273                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 274                     .iinc(3, 1)
 275                     .goto_("loop2")
 276                     .label("end2")
 277                     .iconst_1()
 278                     .return_(TypeTag.Z)
 279                     .label("failed")
 280                     .iconst_0()
 281                     .return_(TypeTag.Z);
 282                 });
 283         boolean result = (boolean) fromExecStackToValueArray.invokeExact();
 284         System.out.println(result);
 285         assertTrue(result, "Invariant");
 286     }
 287 }