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 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 .aconst_init(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 }