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  */
  66 public class ValueTypesTest {
  67 
  68     public static void main(String[] args) {
  69         Class<?> inlineClass = runtime.valhalla.valuetypes.TestValue1.class;
  70         Class<?> testClasses[] = {
  71                 runtime.valhalla.valuetypes.TestValue1.class,
  72                 runtime.valhalla.valuetypes.TestValue2.class,
  73                 runtime.valhalla.valuetypes.TestValue3.class,
  74                 runtime.valhalla.valuetypes.TestValue4.class
  75         };
  76         Class<?> containerClasses[] = {
  77                 runtime.valhalla.valuetypes.ContainerValue1.class,
  78                 runtime.valhalla.valuetypes.ContainerValue2.class,
  79                 runtime.valhalla.valuetypes.ContainerValue3.class,
  80                 runtime.valhalla.valuetypes.ContainerValue4.class
  81         };
  82 
  83         for (int i = 0; i < testClasses.length; i++) {
  84             try {
  85                 testExecutionStackToLocalVariable(testClasses[i]);
  86                 testExecutionStackToFields(testClasses[i], containerClasses[i]);
  87                 // testExecutionStackToValueArray(testClasses[i], containerClasses[i]);
  88             } catch (Throwable t) {
  89                 t.printStackTrace();
  90                 throw new RuntimeException(t);
  91             }
  92         }
  93     }
  94 
  95     static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
  96 
  97     static void testExecutionStackToLocalVariable(Class<?> inlineClass) throws Throwable {
  98         String sig = "()Q" + inlineClass.getName() + ";";
  99         final String signature = sig.replace('.', '/');
 100         MethodHandle fromExecStackToLocalVar = MethodHandleBuilder.loadCode(
 101                 LOOKUP,
 102                 "execStackToLocalVar",
 103                 MethodType.methodType(boolean.class),
 104                 CODE -> {
 105                     CODE.invokestatic(System.class, "gc", "()V", false);
 106                     int n = -1;
 107                     while (n < 1024) {
 108                         n++;
 109                         CODE
 110                         .invokestatic(inlineClass, "getInstance", signature, false)
 111                         .astore(n);
 112                         n++;
 113                         CODE
 114                         .invokestatic(inlineClass, "getNonBufferedInstance", signature, false)
 115                         .astore(n);
 116                     }
 117                     CODE.invokestatic(System.class, "gc", "()V", false);
 118                     while (n > 0) {
 119                         CODE
 120                         .aload(n)
 121                         .invokevirtual(inlineClass, "verify", "()Z", false)
 122                         .iconst_1()
 123                         .ifcmp(TypeTag.I, CondKind.NE, "end");
 124                         n--;
 125                     }
 126                     CODE
 127                     .iconst_1()
 128                     .return_(TypeTag.Z)
 129                     .label("end")
 130                     .iconst_0()
 131                     .return_(TypeTag.Z);
 132                 });
 133         boolean result = (boolean) fromExecStackToLocalVar.invokeExact();
 134         System.out.println(result);
 135         assertTrue(result, "Invariant");
 136     }
 137 
 138     static void testExecutionStackToFields(Class<?> inlineClass, Class<?> containerClass) throws Throwable {
 139         final int ITERATIONS = Platform.isDebugBuild() ? 3 : 512;
 140         String sig = "()Q" + inlineClass.getName() + ";";
 141         final String methodSignature = sig.replace('.', '/');
 142         final String fieldQSignature = "Q" + inlineClass.getName().replace('.', '/') + ";";
 143         final String fieldLSignature = "L" + inlineClass.getName().replace('.', '/') + ";";
 144         System.out.println(methodSignature);
 145         MethodHandle fromExecStackToFields = MethodHandleBuilder.loadCode(
 146                 LOOKUP,
 147                 "execStackToFields",
 148                 MethodType.methodType(boolean.class),
 149                 CODE -> {
 150                     CODE
 151                     .invokestatic(System.class, "gc", "()V", false)
 152                     .new_(containerClass)
 153                     .dup()
 154                     .invoke(MacroCodeBuilder.InvocationKind.INVOKESPECIAL, containerClass, "<init>", "()V", false)
 155                     .astore_1()
 156                     .iconst_m1()
 157                     .istore_2()
 158                     .label("loop")
 159                     .iload_2()
 160                     .ldc(ITERATIONS)
 161                     .ifcmp(TypeTag.I, CondKind.EQ, "end")
 162                     .aload_1()
 163                     .invokestatic(inlineClass, "getInstance", methodSignature, false)
 164                     .putfield(containerClass, "nonStaticValueField", fieldQSignature)
 165                     .invokestatic(System.class, "gc", "()V", false)
 166                     .aload_1()
 167                     .getfield(containerClass, "nonStaticValueField", fieldQSignature)
 168                     .invokevirtual(inlineClass, "verify", "()Z", false)
 169                     .iconst_1()
 170                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 171                     .aload_1()
 172                     .invokestatic(inlineClass, "getNonBufferedInstance", methodSignature, false)
 173                     .putfield(containerClass, "nonStaticValueField", fieldQSignature)
 174                     .invokestatic(System.class, "gc", "()V", false)
 175                     .aload_1()
 176                     .getfield(containerClass, "nonStaticValueField", fieldQSignature)
 177                     .invokevirtual(inlineClass, "verify", "()Z", false)
 178                     .iconst_1()
 179                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 180                     .invokestatic(inlineClass, "getInstance", methodSignature, false)
 181                     .putstatic(containerClass, "staticValueField", fieldLSignature)
 182                     .invokestatic(System.class, "gc", "()V", false)
 183                     .getstatic(containerClass, "staticValueField", fieldLSignature)
 184                     .invokevirtual(inlineClass, "verify", "()Z", false)
 185                     .iconst_1()
 186                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 187                     .invokestatic(inlineClass, "getNonBufferedInstance", methodSignature, false)
 188                     .putstatic(containerClass, "staticValueField", fieldLSignature)
 189                     .invokestatic(System.class, "gc", "()V", false)
 190                     .getstatic(containerClass, "staticValueField", fieldLSignature)
 191                     .invokevirtual(inlineClass, "verify", "()Z", false)
 192                     .iconst_1()
 193                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 194                     .iinc(2, 1)
 195                     .goto_("loop")
 196                     .label("end")
 197                     .iconst_1()
 198                     .return_(TypeTag.Z)
 199                     .label("failed")
 200                     .iconst_0()
 201                     .return_(TypeTag.Z);
 202                 });
 203         boolean result = (boolean) fromExecStackToFields.invokeExact();
 204         System.out.println(result);
 205         assertTrue(result, "Invariant");
 206     }
 207 
 208     static void testExecutionStackToValueArray(Class<?> inlineClass, Class<?> containerClass) throws Throwable {
 209         final int ITERATIONS = Platform.isDebugBuild() ? 3 : 100;
 210         String sig = "()Q" + inlineClass.getName() + ";";
 211         final String signature = sig.replace('.', '/');
 212         final String arraySignature = "[L" + inlineClass.getName().replace('.', '/') + ";";
 213         System.out.println(arraySignature);
 214         MethodHandle fromExecStackToValueArray = MethodHandleBuilder.loadCode(
 215                 LOOKUP,
 216                 "execStackToValueArray",
 217                 MethodType.methodType(boolean.class),
 218                 CODE -> {
 219                     CODE
 220                     .invokestatic(System.class, "gc", "()V", false)
 221                     .new_(containerClass)
 222                     .dup()
 223                     .invoke(MacroCodeBuilder.InvocationKind.INVOKESPECIAL, containerClass, "<init>", "()V", false)
 224                     .astore_1()
 225                     .ldc(ITERATIONS * 3)
 226                     .anewarray(inlineClass)
 227                     .astore_2()
 228                     .aload_2()
 229                     .aload_1()
 230                     .swap()
 231                     .putfield(containerClass, "valueArray", arraySignature)
 232                     .iconst_0()
 233                     .istore_3()
 234                     .label("loop1")
 235                     .iload_3()
 236                     .ldc(ITERATIONS)
 237                     .ifcmp(TypeTag.I, CondKind.GE, "end1")
 238                     .aload_2()
 239                     .iload_3()
 240                     .invokestatic(inlineClass, "getInstance", signature, false)
 241                     .aastore()
 242                     .iinc(3, 1)
 243                     .aload_2()
 244                     .iload_3()
 245                     .invokestatic(inlineClass, "getNonBufferedInstance", signature, false)
 246                     .aastore()
 247                     .iinc(3, 1)
 248                     .aload_2()
 249                     .iload_3()
 250                     .defaultvalue(inlineClass)
 251                     .aastore()
 252                     .iinc(3, 1)
 253                     .goto_("loop1")
 254                     .label("end1")
 255                     .invokestatic(System.class, "gc", "()V", false)
 256                     .iconst_0()
 257                     .istore_3()
 258                     .label("loop2")
 259                     .iload_3()
 260                     .ldc(ITERATIONS * 3)
 261                     .ifcmp(TypeTag.I, CondKind.GE, "end2")
 262                     .aload_2()
 263                     .iload_3()
 264                     .aaload()
 265                     .invokevirtual(inlineClass, "verify", "()Z", false)
 266                     .iconst_1()
 267                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
 268                     .iinc(3, 1)
 269                     .goto_("loop2")
 270                     .label("end2")
 271                     .iconst_1()
 272                     .return_(TypeTag.Z)
 273                     .label("failed")
 274                     .iconst_0()
 275                     .return_(TypeTag.Z);
 276                 });
 277         boolean result = (boolean) fromExecStackToValueArray.invokeExact();
 278         System.out.println(result);
 279         assertTrue(result, "Invariant");
 280     }
 281 }