1 /* 2 * Copyright (c) 2024, 2025, 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 8348961 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 8348961 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.LooselyConsistentValue; 56 57 public class TestFlatInArraysFolding { 58 static Object[] oArrArr = new Object[100][100]; 59 static Object[] oArr = new Object[100]; 60 static Object o = new Object(); 61 static Object[] oArrSmall = new Object[2]; 62 static Object[] vArr = new V[2]; 63 static { 64 oArrSmall[0] = new Object(); 65 oArrSmall[1] = new Object(); 66 vArr[0] = new V(); 67 vArr[1] = new V(); 68 } 69 static int limit = 2; 70 71 // Make sure these are loaded such that A has a flat in array and a not flat in array sub class. 72 static FlatInArray flat = new FlatInArray(34); 73 static NotFlatInArray notFlat = new NotFlatInArray(34); 74 75 // Make sure PUnique is the unique concrete sub class loaded from AUnique. 76 static PUnique pUnique = new PUnique(34); 77 78 static int iFld; 79 80 public static void main(String[] args) { 81 // TODO 8350865 Scenarios are equivalent, FlatArrayElementMaxSize does not exist anymore 82 Scenario flatArrayElementMaxSize1Scenario = new Scenario(1, "-XX:-UseArrayFlattening"); 83 Scenario flatArrayElementMaxSize4Scenario = new Scenario(2, "-XX:-UseArrayFlattening"); 84 Scenario noFlagsScenario = new Scenario(3); 85 TestFramework testFramework = new TestFramework(); 86 testFramework.setDefaultWarmup(0) 87 .addFlags("--enable-preview", 88 "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", 89 "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED") 90 .addScenarios(flatArrayElementMaxSize1Scenario, 91 flatArrayElementMaxSize4Scenario, noFlagsScenario); 92 93 if (args.length > 0) { 94 // Disable Loop Unrolling for IR matching in testCmpP(). 95 // Use IgnoreUnrecognizedVMOptions since LoopMaxUnroll is a C2 flag. 96 // testSubTypeCheck() only triggers with SerialGC. 97 Scenario serialGCScenario = new Scenario(4, "-XX:+UseSerialGC", "-XX:+IgnoreUnrecognizedVMOptions", 98 "-XX:LoopMaxUnroll=0"); 99 testFramework.addScenarios(serialGCScenario); 100 } 101 Scenario noMethodTraps = new Scenario(5, "-XX:PerMethodTrapLimit=0", "-Xbatch"); 102 testFramework.addScenarios(noMethodTraps); 103 testFramework.start(); 104 } 105 106 // SubTypeCheck is not folded while CheckCastPPNode is replaced by top which results in a bad graph (data dies while 107 // control does not). 108 @Test 109 static void testSubTypeCheck() { 110 for (int i = 0; i < 100; i++) { 111 Object arrayElement = oArrArr[i]; 112 oArr = (Object[])arrayElement; 113 } 114 } 115 116 @Test 117 @IR(counts = {IRNode.COUNTED_LOOP, "2", // Loop Unswitching done? 118 IRNode.STORE_I, "1"}, // CmpP folded in unswitched loop version with flat in array? 119 applyIf = {"LoopMaxUnroll", "0"}) 120 static void testCmpP() { 121 for (int i = 0; i < 100; i++) { 122 Object arrayElement = oArrArr[i]; 123 if (arrayElement == oArr) { 124 iFld = 34; 125 } 126 } 127 } 128 129 // Type system does not correctly handle the case that a super klass is flat in array while the sub klass is 130 // maybe flat in array. This leads to a bad graph. 131 @Test 132 static void testUnswitchingAbstractClass() { 133 Object[] arr = oArr; 134 for (int i = 0; i < 100; i++) { 135 Object arrayElement = arr[i]; 136 if (arrayElement instanceof A) { 137 A a = (A)arrayElement; 138 if (a == o) { 139 a.foo(); 140 } 141 } 142 } 143 } 144 145 // Same as testUnswitchingAbstractClass() but with interfaces. This worked before because I has type Object(I) 146 // from which Object is a sub type of. 147 @Test 148 static void testUnswitchingInterface() { 149 Object[] arr = oArr; 150 for (int i = 0; i < 100; i++) { 151 Object arrayElement = arr[i]; 152 if (arrayElement instanceof I) { 153 I iVar = (I)arrayElement; 154 if (iVar == o) { 155 iVar.bar(); 156 } 157 } 158 } 159 } 160 161 // TODO 8350865 FlatArrayElementMaxSize does not exist anymore 162 // PUnique is the unique concrete sub class of AUnique and is not flat in array (with FlatArrayElementMaxSize=4). 163 // The CheckCastPP output of the sub type check uses PUnique while the sub type check itself uses AUnique. This leads 164 // to a bad graph because the type system determines that the flat in array super klass cannot be met with the 165 // not flat in array sub klass. But the sub type check does not fold away because AUnique *could* be flat in array. 166 // Fixed with in JDK-8328480 in mainline but not yet merged in. Applied manually to make this work. 167 @Test 168 static void testSubTypeCheckNotFoldedParsingAbstractClass() { 169 Object[] arr = oArr; 170 for (int i = 0; i < 100; i++) { 171 Object arrayElement = arr[i]; 172 if (arrayElement instanceof AUnique) { 173 AUnique aUnique = (AUnique)arrayElement; 174 if (aUnique == o) { 175 aUnique.foo(); 176 } 177 } 178 } 179 } 180 181 // Same as testSubTypeCheckNotFoldedParsingAbstractClass() but with interfaces. This worked before because IUnique 182 // has type Object(IUnique) from which Object is a sub type of. 183 @Test 184 static void testSubTypeCheckNotFoldedParsingInterface() { 185 Object[] arr = oArr; 186 for (int i = 0; i < 100; i++) { 187 Object arrayElement = arr[i]; 188 if (arrayElement instanceof IUnique) { 189 IUnique iUnique = (IUnique)arrayElement; 190 if (iUnique == o) { 191 iUnique.bar(); 192 } 193 } 194 } 195 } 196 197 @Test 198 @Warmup(10000) 199 static void testJoinSameKlassDifferentFlatInArray() { 200 // Accessing the array: It could be a flat array. We therefore add a Phi to select from the normal vs. 201 // flat in array access: 202 // Phi(Object:flat_in_array, Object) -> CheckCastPP[Object:NotNull:exact] 203 for (Object o : oArrSmall) { 204 // We speculate that we always call Object::hashCode() and thus add a CheckCastPP[Object:NotNull:exact] 205 // together with a speculate_class_check trap on the failing path. 206 // We decide to unswitch the loop to get a loop version where we only have flat in array accesses. This 207 // means we can get rid of the Phi. During IGVN and folding some nodes we eventually end up with: 208 // CheckCastPP[Object:NotNull (flat_in_array)] -> CheckCastPP[Object:NotNull:exact] 209 // 210 // We know that we have some kind of Value class that needs to be joined with an exact Object that is not 211 // a value class. Thus, the result in an empty set. But this is missing in the type system. We fail with 212 // an assertion. This is fixed with 8348961. 213 // 214 // To make this type system change work, we require that the TypeInstKlassPtr::not_flat_in_array() takes 215 // exactness information into account to also fold the corresponding control path. This requires another 216 // follow up fix: The super class of a sub type check is always an exact class, i.e. "o instanceof Super". 217 // We need a version of TypeInstKlassPtr::not_flat_in_array() that treats "Super" as inexact. Failing to do 218 // so will erroneously fold a sub type check away (covered by testSubTypeCheckForObjectReceiver()). 219 o.hashCode(); 220 } 221 } 222 223 @Test 224 @Warmup(10000) 225 static void testSubTypeCheckForObjectReceiver() { 226 for (int i = 0; i < limit; i++) { 227 // We perform a sub type check that V is a sub type of Object. This is obviously true 228 vArr[i].hashCode(); 229 } 230 } 231 232 interface IUnique { 233 abstract void bar(); 234 } 235 236 static abstract value class AUnique implements IUnique { 237 abstract void foo(); 238 } 239 240 @LooselyConsistentValue 241 static value class PUnique extends AUnique { 242 int x; 243 int y; 244 PUnique(int x) { 245 this.x = x; 246 this.y = 34; 247 } 248 249 public void foo() {} 250 public void bar() {} 251 } 252 253 interface I { 254 void bar(); 255 } 256 257 static abstract value class A implements I { 258 abstract void foo(); 259 } 260 261 @LooselyConsistentValue 262 static value class FlatInArray extends A implements I { 263 int x; 264 FlatInArray(int x) { 265 this.x = x; 266 } 267 268 public void foo() {} 269 public void bar() {} 270 } 271 272 // TODO 8350865 FlatArrayElementMaxSize does not exist anymore 273 // Not flat in array with -XX:FlatArrayElementMaxSize=4 274 static value class NotFlatInArray extends A implements I { 275 int x; 276 int y; 277 NotFlatInArray(int x) { 278 this.x = x; 279 this.y = 34; 280 } 281 282 public void foo() {} 283 public void bar() {} 284 } 285 286 static value class V {} 287 }