1 /*
  2  * Copyright (c) 2017, 2022, 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.inlinetypes;
 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 javax.tools.*;
 45 import test.java.lang.invoke.lib.InstructionHelper;
 46 
 47 /**
 48  * @test InlineTypesTest
 49  * @summary Test data movement with inline types
 50  * @modules java.base/jdk.internal.value
 51  * @library /test/lib /test/jdk/lib/testlibrary/bytecode /test/jdk/java/lang/invoke/common
 52  * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
 53  * @compile -XDenablePrimitiveClasses TestValue1.java TestValue2.java TestValue3.java TestValue4.java InlineTypesTest.java
 54  * @run main/othervm -XX:+EnableValhalla -XX:+EnablePrimitiveClasses
 55  *                   -Xmx128m -XX:+ExplicitGCInvokesConcurrent
 56  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
 57  *                   -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=false
 58  *                   runtime.valhalla.inlinetypes.InlineTypesTest
 59  * @run main/othervm -XX:+EnableValhalla -XX:+EnablePrimitiveClasses
 60  *                   -Xmx128m -XX:+ExplicitGCInvokesConcurrent
 61  *                   -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
 62  *                   -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=false
 63  *                   -XX:ForceNonTearable=*
 64  *                   runtime.valhalla.inlinetypes.InlineTypesTest
 65  */
 66 public class InlineTypesTest {
 67 
 68     public static void main(String[] args) {
 69         Class<?> inlineClass = runtime.valhalla.inlinetypes.TestValue1.class;
 70         Class<?> testClasses[] = {
 71                 runtime.valhalla.inlinetypes.TestValue1.class,
 72                 runtime.valhalla.inlinetypes.TestValue2.class,
 73                 runtime.valhalla.inlinetypes.TestValue3.class,
 74                 runtime.valhalla.inlinetypes.TestValue4.class
 75         };
 76         Class<?> containerClasses[] = {
 77                 runtime.valhalla.inlinetypes.ContainerValue1.class,
 78                 runtime.valhalla.inlinetypes.ContainerValue2.class,
 79                 runtime.valhalla.inlinetypes.ContainerValue3.class,
 80                 runtime.valhalla.inlinetypes.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                 // testExecutionStackToInlineArray(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 = InstructionHelper.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 = InstructionHelper.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, "nonStaticInlineField", fieldQSignature)
165                     .invokestatic(System.class, "gc", "()V", false)
166                     .aload_1()
167                     .getfield(containerClass, "nonStaticInlineField", 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, "nonStaticInlineField", fieldQSignature)
174                     .invokestatic(System.class, "gc", "()V", false)
175                     .aload_1()
176                     .getfield(containerClass, "nonStaticInlineField", 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, "staticInlineField", fieldLSignature)
182                     .invokestatic(System.class, "gc", "()V", false)
183                     .getstatic(containerClass, "staticInlineField", fieldLSignature)
184                     .checkcast(inlineClass)
185                     .invokevirtual(inlineClass, "verify", "()Z", false)
186                     .iconst_1()
187                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
188                     .invokestatic(inlineClass, "getNonBufferedInstance", methodSignature, false)
189                     .putstatic(containerClass, "staticInlineField", fieldLSignature)
190                     .invokestatic(System.class, "gc", "()V", false)
191                     .getstatic(containerClass, "staticInlineField", fieldLSignature)
192                     .checkcast(inlineClass)
193                     .invokevirtual(inlineClass, "verify", "()Z", false)
194                     .iconst_1()
195                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
196                     .iinc(2, 1)
197                     .goto_("loop")
198                     .label("end")
199                     .iconst_1()
200                     .return_(TypeTag.Z)
201                     .label("failed")
202                     .iconst_0()
203                     .return_(TypeTag.Z);
204                 });
205         boolean result = (boolean) fromExecStackToFields.invokeExact();
206         System.out.println(result);
207         assertTrue(result, "Invariant");
208     }
209 
210     static void testExecutionStackToInlineArray(Class<?> inlineClass, Class<?> containerClass) throws Throwable {
211         final int ITERATIONS = Platform.isDebugBuild() ? 3 : 100;
212         String sig = "()Q" + inlineClass.getName() + ";";
213         final String signature = sig.replace('.', '/');
214         final String arraySignature = "[L" + inlineClass.getName().replace('.', '/') + ";";
215         System.out.println(arraySignature);
216         MethodHandle fromExecStackToInlineArray = InstructionHelper.loadCode(
217                 LOOKUP,
218                 "execStackToInlineArray",
219                 MethodType.methodType(boolean.class),
220                 CODE -> {
221                     CODE
222                     .invokestatic(System.class, "gc", "()V", false)
223                     .new_(containerClass)
224                     .dup()
225                     .invoke(MacroCodeBuilder.InvocationKind.INVOKESTATIC, containerClass, "<vnew>", "()V", false)
226                     .astore_1()
227                     .ldc(ITERATIONS * 3)
228                     .anewarray(inlineClass)
229                     .astore_2()
230                     .aload_2()
231                     .aload_1()
232                     .swap()
233                     .putfield(containerClass, "valueArray", arraySignature)
234                     .iconst_0()
235                     .istore_3()
236                     .label("loop1")
237                     .iload_3()
238                     .ldc(ITERATIONS)
239                     .ifcmp(TypeTag.I, CondKind.GE, "end1")
240                     .aload_2()
241                     .iload_3()
242                     .invokestatic(inlineClass, "getInstance", signature, false)
243                     .aastore()
244                     .iinc(3, 1)
245                     .aload_2()
246                     .iload_3()
247                     .invokestatic(inlineClass, "getNonBufferedInstance", signature, false)
248                     .aastore()
249                     .iinc(3, 1)
250                     .aload_2()
251                     .iload_3()
252                     .aconst_init(inlineClass)
253                     .aastore()
254                     .iinc(3, 1)
255                     .goto_("loop1")
256                     .label("end1")
257                     .invokestatic(System.class, "gc", "()V", false)
258                     .iconst_0()
259                     .istore_3()
260                     .label("loop2")
261                     .iload_3()
262                     .ldc(ITERATIONS * 3)
263                     .ifcmp(TypeTag.I, CondKind.GE, "end2")
264                     .aload_2()
265                     .iload_3()
266                     .aaload()
267                     .invokevirtual(inlineClass, "verify", "()Z", false)
268                     .iconst_1()
269                     .ifcmp(TypeTag.I, CondKind.NE, "failed")
270                     .iinc(3, 1)
271                     .goto_("loop2")
272                     .label("end2")
273                     .iconst_1()
274                     .return_(TypeTag.Z)
275                     .label("failed")
276                     .iconst_0()
277                     .return_(TypeTag.Z);
278                 });
279         boolean result = (boolean) fromExecStackToInlineArray.invokeExact();
280         System.out.println(result);
281         assertTrue(result, "Invariant");
282     }
283 }