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