1 /* 2 * Copyright (c) 2024, 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 /* 25 * @test id=serialgc 26 * @bug 8321734 27 * @requires vm.gc.Serial 28 * @summary Test that CmpPNode::sub and SubTypeCheckNode::sub correctly identify unrelated classes based on the flat 29 * in array property of the types. Additionally check that the type system properly handles the case of a 30 * super class being flat in array while the sub klass could be flat in array. 31 * @library /test/lib / 32 * @enablePreview 33 * @modules java.base/jdk.internal.value 34 * java.base/jdk.internal.vm.annotation 35 * @run main compiler.valhalla.inlinetypes.TestFlatInArraysFolding serial 36 */ 37 38 /* 39 * @test 40 * @bug 8321734 41 * @summary Test that CmpPNode::sub and SubTypeCheckNode::sub correctly identify unrelated classes based on the flat 42 * in array property of the types. Additionally check that the type system properly handles the case of a 43 * super class being flat in array while the sub klass could be flat in array. 44 * @library /test/lib / 45 * @enablePreview 46 * @modules java.base/jdk.internal.value 47 * java.base/jdk.internal.vm.annotation 48 * @run main compiler.valhalla.inlinetypes.TestFlatInArraysFolding 49 */ 50 51 package compiler.valhalla.inlinetypes; 52 53 import compiler.lib.ir_framework.*; 54 55 import jdk.internal.vm.annotation.ImplicitlyConstructible; 56 import jdk.internal.vm.annotation.LooselyConsistentValue; 57 58 public class TestFlatInArraysFolding { 59 static Object[] oArrArr = new Object[100][100]; 60 static Object[] oArr = new Object[100]; 61 static Object o = new Object(); 62 63 // Make sure these are loaded such that A has a flat in array and a not flat in array sub class. 64 static FlatInArray flat = new FlatInArray(34); 65 static NotFlatInArray notFlat = new NotFlatInArray(34); 66 67 // Make sure PUnique is the unique concrete sub class loaded from AUnique. 68 static PUnique pUnique = new PUnique(34); 69 70 static int iFld; 71 72 public static void main(String[] args) { 73 Scenario flatArrayElementMaxSize1Scenario = new Scenario(1, "-XX:FlatArrayElementMaxSize=1"); 74 Scenario flatArrayElementMaxSize4Scenario = new Scenario(2, "-XX:FlatArrayElementMaxSize=4"); 75 Scenario noFlagsScenario = new Scenario(3); 76 TestFramework testFramework = new TestFramework(); 77 testFramework.setDefaultWarmup(0) 78 .addFlags("--enable-preview", 79 "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", 80 "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED") 81 .addScenarios(flatArrayElementMaxSize1Scenario, 82 flatArrayElementMaxSize4Scenario, noFlagsScenario); 83 84 if (args.length > 0) { 85 // Disable Loop Unrolling for IR matching in testCmpP(). 86 // Use IgnoreUnrecognizedVMOptions since LoopMaxUnroll is a C2 flag. 87 // testSubTypeCheck() only triggers with SerialGC. 88 Scenario serialGCScenario = new Scenario(4, "-XX:+UseSerialGC", "-XX:+IgnoreUnrecognizedVMOptions", 89 "-XX:LoopMaxUnroll=0"); 90 testFramework.addScenarios(serialGCScenario); 91 } 92 testFramework.start(); 93 } 94 95 // SubTypeCheck is not folded while CheckCastPPNode is replaced by top which results in a bad graph (data dies while 96 // control does not). 97 @Test 98 static void testSubTypeCheck() { 99 for (int i = 0; i < 100; i++) { 100 Object arrayElement = oArrArr[i]; 101 oArr = (Object[])arrayElement; 102 } 103 } 104 105 @Test 106 @IR(counts = {IRNode.COUNTED_LOOP, "2", // Loop Unswitching done? 107 IRNode.STORE_I, "1"}, // CmpP folded in unswitched loop version with flat in array? 108 applyIf = {"LoopMaxUnroll", "0"}) 109 static void testCmpP() { 110 for (int i = 0; i < 100; i++) { 111 Object arrayElement = oArrArr[i]; 112 if (arrayElement == oArr) { 113 iFld = 34; 114 } 115 } 116 } 117 118 // Type system does not correctly handle the case that a super klass is flat in array while the sub klass is 119 // maybe flat in array. This leads to a bad graph. 120 @Test 121 static void testUnswitchingAbstractClass() { 122 Object[] arr = oArr; 123 for (int i = 0; i < 100; i++) { 124 Object arrayElement = arr[i]; 125 if (arrayElement instanceof A) { 126 A a = (A)arrayElement; 127 if (a == o) { 128 a.foo(); 129 } 130 } 131 } 132 } 133 134 // Same as testUnswitchingAbstractClass() but with interfaces. This worked before because I has type Object(I) 135 // from which Object is a sub type of. 136 @Test 137 static void testUnswitchingInterface() { 138 Object[] arr = oArr; 139 for (int i = 0; i < 100; i++) { 140 Object arrayElement = arr[i]; 141 if (arrayElement instanceof I) { 142 I iVar = (I)arrayElement; 143 if (iVar == o) { 144 iVar.bar(); 145 } 146 } 147 } 148 } 149 150 // PUnique is the unique concrete sub class of AUnique and is not flat in array (with FlatArrayElementMaxSize=4). 151 // The CheckCastPP output of the sub type check uses PUnique while the sub type check itself uses AUnique. This leads 152 // to a bad graph because the type system determines that the flat in array super klass cannot be met with the 153 // not flat in array sub klass. But the sub type check does not fold away because AUnique *could* be flat in array. 154 // Fixed with in JDK-8328480 in mainline but not yet merged in. Applied manually to make this work. 155 @Test 156 static void testSubTypeCheckNotFoldedParsingAbstractClass() { 157 Object[] arr = oArr; 158 for (int i = 0; i < 100; i++) { 159 Object arrayElement = arr[i]; 160 if (arrayElement instanceof AUnique) { 161 AUnique aUnique = (AUnique)arrayElement; 162 if (aUnique == o) { 163 aUnique.foo(); 164 } 165 } 166 } 167 } 168 169 // Same as testSubTypeCheckNotFoldedParsingAbstractClass() but with interfaces. This worked before because IUnique 170 // has type Object(IUnique) from which Object is a sub type of. 171 @Test 172 static void testSubTypeCheckNotFoldedParsingInterface() { 173 Object[] arr = oArr; 174 for (int i = 0; i < 100; i++) { 175 Object arrayElement = arr[i]; 176 if (arrayElement instanceof IUnique) { 177 IUnique iUnique = (IUnique)arrayElement; 178 if (iUnique == o) { 179 iUnique.bar(); 180 } 181 } 182 } 183 } 184 185 interface IUnique { 186 abstract void bar(); 187 } 188 189 static abstract value class AUnique implements IUnique { 190 abstract void foo(); 191 } 192 193 @ImplicitlyConstructible 194 @LooselyConsistentValue 195 static value class PUnique extends AUnique { 196 int x; 197 int y; 198 PUnique(int x) { 199 this.x = x; 200 this.y = 34; 201 } 202 203 public void foo() {} 204 public void bar() {} 205 } 206 207 interface I { 208 void bar(); 209 } 210 211 static abstract value class A implements I { 212 abstract void foo(); 213 } 214 215 @ImplicitlyConstructible 216 @LooselyConsistentValue 217 static value class FlatInArray extends A implements I { 218 int x; 219 FlatInArray(int x) { 220 this.x = x; 221 } 222 223 public void foo() {} 224 public void bar() {} 225 } 226 227 // Not flat in array with -XX:FlatArrayElementMaxSize=4 228 static value class NotFlatInArray extends A implements I { 229 int x; 230 int y; 231 NotFlatInArray(int x) { 232 this.x = x; 233 this.y = 34; 234 } 235 236 public void foo() {} 237 public void bar() {} 238 } 239 }