1 /* 2 * Copyright (c) 2020 SAP SE. 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 /** 26 * @test 27 * @bug 8227745 28 * @summary Collection of test cases that check if optimizations based on escape analysis are reverted just before non-escaping objects escape through JVMTI. 29 * @author Richard Reingruber richard DOT reingruber AT sap DOT com 30 * 31 * @requires ((vm.compMode == "Xmixed") & vm.compiler2.enabled) 32 * @library /test/lib /test/hotspot/jtreg 33 * 34 * @run build TestScaffold VMConnection TargetListener TargetAdapter jdk.test.whitebox.WhiteBox 35 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 36 * @run compile -g EATests.java 37 * @run driver EATests 38 * -XX:+UnlockDiagnosticVMOptions 39 * -Xms256m -Xmx256m 40 * -Xbootclasspath/a:. 41 * -XX:CompileCommand=dontinline,*::dontinline_* 42 * -XX:+WhiteBoxAPI 43 * -Xbatch 44 * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks 45 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=1 46 * @run driver EATests 47 * -XX:+UnlockDiagnosticVMOptions 48 * -Xms256m -Xmx256m 49 * -Xbootclasspath/a:. 50 * -XX:CompileCommand=dontinline,*::dontinline_* 51 * -XX:+WhiteBoxAPI 52 * -Xbatch 53 * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:-EliminateLocks -XX:+EliminateNestedLocks 54 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=1 55 * @run driver EATests 56 * -XX:+UnlockDiagnosticVMOptions 57 * -Xms256m -Xmx256m 58 * -Xbootclasspath/a:. 59 * -XX:CompileCommand=dontinline,*::dontinline_* 60 * -XX:+WhiteBoxAPI 61 * -Xbatch 62 * -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks 63 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=1 64 * @run driver EATests 65 * -XX:+UnlockDiagnosticVMOptions 66 * -Xms256m -Xmx256m 67 * -Xbootclasspath/a:. 68 * -XX:CompileCommand=dontinline,*::dontinline_* 69 * -XX:+WhiteBoxAPI 70 * -Xbatch 71 * -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks 72 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=1 73 * 74 * @run driver EATests 75 * -XX:+UnlockDiagnosticVMOptions 76 * -Xms256m -Xmx256m 77 * -Xbootclasspath/a:. 78 * -XX:CompileCommand=dontinline,*::dontinline_* 79 * -XX:+WhiteBoxAPI 80 * -Xbatch 81 * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks 82 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=2 83 * @run driver EATests 84 * -XX:+UnlockDiagnosticVMOptions 85 * -Xms256m -Xmx256m 86 * -Xbootclasspath/a:. 87 * -XX:CompileCommand=dontinline,*::dontinline_* 88 * -XX:+WhiteBoxAPI 89 * -Xbatch 90 * -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:-EliminateLocks -XX:+EliminateNestedLocks 91 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=2 92 * @run driver EATests 93 * -XX:+UnlockDiagnosticVMOptions 94 * -Xms256m -Xmx256m 95 * -Xbootclasspath/a:. 96 * -XX:CompileCommand=dontinline,*::dontinline_* 97 * -XX:+WhiteBoxAPI 98 * -Xbatch 99 * -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks 100 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=2 101 * @run driver EATests 102 * -XX:+UnlockDiagnosticVMOptions 103 * -Xms256m -Xmx256m 104 * -Xbootclasspath/a:. 105 * -XX:CompileCommand=dontinline,*::dontinline_* 106 * -XX:+WhiteBoxAPI 107 * -Xbatch 108 * -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks 109 * -XX:+UnlockExperimentalVMOptions -XX:LockingMode=2 110 * 111 * @comment Excercise -XX:+DeoptimizeObjectsALot. Mostly to prevent bit-rot because the option is meant to stress object deoptimization 112 * with non-synthetic workloads. 113 * @run driver EATests 114 * -XX:+UnlockDiagnosticVMOptions 115 * -Xms256m -Xmx256m 116 * -Xbootclasspath/a:. 117 * -XX:CompileCommand=dontinline,*::dontinline_* 118 * -XX:+WhiteBoxAPI 119 * -Xbatch 120 * -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks 121 * -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeObjectsALot 122 * 123 */ 124 /** 125 * @test 126 * @bug 8227745 127 * 128 * @summary This is another configuration of EATests.java to test Graal. Some testcases are expected 129 * to fail because Graal does not provide all information about non-escaping objects in 130 * scope. These are skipped. 131 * 132 * @author Richard Reingruber richard DOT reingruber AT sap DOT com 133 * 134 * @requires ((vm.compMode == "Xmixed") & vm.graal.enabled) 135 * 136 * @library /test/lib /test/hotspot/jtreg 137 * 138 * @run build TestScaffold VMConnection TargetListener TargetAdapter jdk.test.whitebox.WhiteBox 139 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 140 * @run compile -g EATests.java 141 * 142 * @comment Test with Graal. Some testcases are expected to fail because Graal does not provide all information about non-escaping 143 * objects in scope. These are skipped. 144 * @run driver EATests 145 * -XX:+UnlockDiagnosticVMOptions 146 * -Xms256m -Xmx256m 147 * -Xbootclasspath/a:. 148 * -XX:CompileCommand=dontinline,*::dontinline_* 149 * -XX:+WhiteBoxAPI 150 * -Xbatch 151 * -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler 152 */ 153 154 import com.sun.jdi.*; 155 import com.sun.jdi.event.*; 156 import compiler.testlibrary.CompilerUtils; 157 import compiler.whitebox.CompilerWhiteBoxTest; 158 159 import java.lang.reflect.Array; 160 import java.util.Arrays; 161 import java.util.List; 162 import java.util.Map; 163 import java.util.function.Function; 164 165 import jdk.test.lib.Asserts; 166 import jdk.test.whitebox.WhiteBox; 167 import jdk.test.whitebox.gc.GC; 168 169 170 // 171 // ANALYZING TEST FAILURES 172 // 173 // - Executing just a single test case with the property EATests.onlytestcase. 174 // 175 // Example: java -DEATests.onlytestcase=<test case name> ... EATests 176 // 177 // - Interactive execution allows for attaching a native debugger, e.g. gdb 178 // 179 // Example: java -DEATests.interactive=true ... EATests 180 // 181 // - Java arguments to the test are passed as vm options to the debuggee: 182 // 183 // Example: java ... EATests -XX:+UseNewCode 184 // 185 186 187 188 ///////////////////////////////////////////////////////////////////////////// 189 // 190 // Shared base class for test cases for both, debugger and debuggee. 191 // 192 ///////////////////////////////////////////////////////////////////////////// 193 194 class EATestCaseBaseShared { 195 // In interactive mode we wait for a keypress before every test case. 196 public static final boolean INTERACTIVE = 197 System.getProperty("EATests.interactive") != null && 198 System.getProperty("EATests.interactive").equals("true"); 199 200 // If the property is given, then just the test case it refers to is executed. 201 // Use it to diagnose test failures. 202 public static final String RUN_ONLY_TEST_CASE_PROPERTY = "EATests.onlytestcase"; 203 public static final String RUN_ONLY_TEST_CASE = System.getProperty(RUN_ONLY_TEST_CASE_PROPERTY); 204 205 public final String testCaseName; 206 207 public EATestCaseBaseShared() { 208 String clName = getClass().getName(); 209 int tidx = clName.lastIndexOf("Target"); 210 testCaseName = tidx > 0 ? clName.substring(0, tidx) : clName; 211 } 212 213 public boolean shouldSkip() { 214 return EATestCaseBaseShared.RUN_ONLY_TEST_CASE != null && 215 EATestCaseBaseShared.RUN_ONLY_TEST_CASE.length() > 0 && 216 !testCaseName.equals(EATestCaseBaseShared.RUN_ONLY_TEST_CASE); 217 } 218 } 219 220 ///////////////////////////////////////////////////////////////////////////// 221 // 222 // Target main class, i.e. the program to be debugged. 223 // 224 ///////////////////////////////////////////////////////////////////////////// 225 226 class EATestsTarget { 227 228 public static void main(String[] args) { 229 EATestCaseBaseTarget.staticSetUp(); 230 EATestCaseBaseTarget.staticSetUpDone(); 231 232 // Materializing test cases, i.e. reallocating objects on the heap 233 new EAMaterializeLocalVariableUponGetTarget() .run(); 234 new EAGetWithoutMaterializeTarget() .run(); 235 new EAMaterializeLocalAtObjectReturnTarget() .run(); 236 new EAMaterializeLocalAtObjectPollReturnReturnTarget() .run(); 237 new EAMaterializeIntArrayTarget() .run(); 238 new EAMaterializeLongArrayTarget() .run(); 239 new EAMaterializeFloatArrayTarget() .run(); 240 new EAMaterializeDoubleArrayTarget() .run(); 241 new EAMaterializeObjectArrayTarget() .run(); 242 new EAMaterializeObjectWithConstantAndNotConstantValuesTarget() .run(); 243 new EAMaterializeObjReferencedBy2LocalsTarget() .run(); 244 new EAMaterializeObjReferencedBy2LocalsAndModifyTarget() .run(); 245 new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesTarget() .run(); 246 new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModifyTarget() .run(); 247 new EAMaterializeObjReferencedFromOperandStackTarget() .run(); 248 new EAMaterializeLocalVariableUponGetAfterSetIntegerTarget() .run(); 249 250 // Relocking test cases 251 new EARelockingSimpleTarget() .run(); 252 new EARelockingSimpleWithAccessInOtherThreadTarget() .run(); 253 new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target() .run(); 254 new EARelockingRecursiveTarget() .run(); 255 new EARelockingNestedInflatedTarget() .run(); 256 new EARelockingNestedInflated_02Target() .run(); 257 new EARelockingArgEscapeLWLockedInCalleeFrameTarget() .run(); 258 new EARelockingArgEscapeLWLockedInCalleeFrame_2Target() .run(); 259 new EARelockingArgEscapeLWLockedInCalleeFrameNoRecursiveTarget() .run(); 260 new EAGetOwnedMonitorsTarget() .run(); 261 new EAEntryCountTarget() .run(); 262 new EARelockingObjectCurrentlyWaitingOnTarget() .run(); 263 264 // Test cases that require deoptimization even though neither 265 // locks nor allocations are eliminated at the point where 266 // escape state is changed. 267 new EADeoptFrameAfterReadLocalObject_01Target() .run(); 268 new EADeoptFrameAfterReadLocalObject_01BTarget() .run(); 269 new EADeoptFrameAfterReadLocalObject_02Target() .run(); 270 new EADeoptFrameAfterReadLocalObject_02BTarget() .run(); 271 new EADeoptFrameAfterReadLocalObject_02CTarget() .run(); 272 new EADeoptFrameAfterReadLocalObject_03Target() .run(); 273 274 // PopFrame test cases 275 new EAPopFrameNotInlinedTarget() .run(); 276 new EAPopFrameNotInlinedReallocFailureTarget() .run(); 277 new EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget() .run(); 278 279 // ForceEarlyReturn test cases 280 new EAForceEarlyReturnNotInlinedTarget() .run(); 281 new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget() .run(); 282 new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget().run(); 283 284 // Instances of ReferenceType 285 new EAGetInstancesOfReferenceTypeTarget() .run(); 286 } 287 } 288 289 ///////////////////////////////////////////////////////////////////////////// 290 // 291 // Debugger main class 292 // 293 ///////////////////////////////////////////////////////////////////////////// 294 295 public class EATests extends TestScaffold { 296 297 public TargetVMOptions targetVMOptions; 298 public ThreadReference targetMainThread; 299 300 EATests(String args[]) { 301 super(args); 302 } 303 304 public static void main(String[] args) throws Exception { 305 if (EATestCaseBaseShared.RUN_ONLY_TEST_CASE != null) { 306 args = Arrays.copyOf(args, args.length + 1); 307 args[args.length - 1] = "-D" + EATestCaseBaseShared.RUN_ONLY_TEST_CASE_PROPERTY + "=" + EATestCaseBaseShared.RUN_ONLY_TEST_CASE; 308 } 309 new EATests(args).startTests(); 310 } 311 312 public static class TargetVMOptions { 313 314 public final boolean UseJVMCICompiler; 315 public final boolean EliminateAllocations; 316 public final boolean DeoptimizeObjectsALot; 317 public final boolean DoEscapeAnalysis; 318 public final boolean ZGCIsSelected; 319 public final boolean ShenandoahGCIsSelected; 320 public final boolean StressReflectiveCode; 321 322 public TargetVMOptions(EATests env, ClassType testCaseBaseTargetClass) { 323 Value val; 324 val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("DoEscapeAnalysis")); 325 DoEscapeAnalysis = ((PrimitiveValue) val).booleanValue(); 326 // Escape analysis is a prerequisite for scalar replacement (EliminateAllocations) 327 val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("EliminateAllocations")); 328 EliminateAllocations = DoEscapeAnalysis && ((PrimitiveValue) val).booleanValue(); 329 val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("DeoptimizeObjectsALot")); 330 DeoptimizeObjectsALot = ((PrimitiveValue) val).booleanValue(); 331 val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("UseJVMCICompiler")); 332 UseJVMCICompiler = ((PrimitiveValue) val).booleanValue(); 333 val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("ZGCIsSelected")); 334 ZGCIsSelected = ((PrimitiveValue) val).booleanValue(); 335 val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("ShenandoahGCIsSelected")); 336 ShenandoahGCIsSelected = ((PrimitiveValue) val).booleanValue(); 337 val = testCaseBaseTargetClass.getValue(testCaseBaseTargetClass.fieldByName("StressReflectiveCode")); 338 StressReflectiveCode = ((PrimitiveValue) val).booleanValue(); 339 } 340 341 } 342 343 // Execute known test cases 344 protected void runTests() throws Exception { 345 String targetProgName = EATestsTarget.class.getName(); 346 msg("starting to main method in class " + targetProgName); 347 startToMain(targetProgName); 348 msg("resuming to EATestCaseBaseTarget.staticSetUpDone()V"); 349 targetMainThread = resumeTo("EATestCaseBaseTarget", "staticSetUpDone", "()V").thread(); 350 Location loc = targetMainThread.frame(0).location(); 351 Asserts.assertEQ("staticSetUpDone", loc.method().name()); 352 353 targetVMOptions = new TargetVMOptions(this, (ClassType) loc.declaringType()); 354 355 // Materializing test cases, i.e. reallocating objects on the heap 356 new EAMaterializeLocalVariableUponGet() .run(this); 357 new EAGetWithoutMaterialize() .run(this); 358 new EAMaterializeLocalAtObjectReturn() .run(this); 359 new EAMaterializeLocalAtObjectPollReturnReturn() .run(this); 360 new EAMaterializeIntArray() .run(this); 361 new EAMaterializeLongArray() .run(this); 362 new EAMaterializeFloatArray() .run(this); 363 new EAMaterializeDoubleArray() .run(this); 364 new EAMaterializeObjectArray() .run(this); 365 new EAMaterializeObjectWithConstantAndNotConstantValues() .run(this); 366 new EAMaterializeObjReferencedBy2Locals() .run(this); 367 new EAMaterializeObjReferencedBy2LocalsAndModify() .run(this); 368 new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFrames() .run(this); 369 new EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModify() .run(this); 370 new EAMaterializeObjReferencedFromOperandStack() .run(this); 371 new EAMaterializeLocalVariableUponGetAfterSetInteger() .run(this); 372 373 // Relocking test cases 374 new EARelockingSimple() .run(this); 375 new EARelockingSimpleWithAccessInOtherThread() .run(this); 376 new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall() .run(this); 377 new EARelockingRecursive() .run(this); 378 new EARelockingNestedInflated() .run(this); 379 new EARelockingNestedInflated_02() .run(this); 380 new EARelockingArgEscapeLWLockedInCalleeFrame() .run(this); 381 new EARelockingArgEscapeLWLockedInCalleeFrame_2() .run(this); 382 new EARelockingArgEscapeLWLockedInCalleeFrameNoRecursive() .run(this); 383 new EAGetOwnedMonitors() .run(this); 384 new EAEntryCount() .run(this); 385 new EARelockingObjectCurrentlyWaitingOn() .run(this); 386 387 // Test cases that require deoptimization even though neither 388 // locks nor allocations are eliminated at the point where 389 // escape state is changed. 390 new EADeoptFrameAfterReadLocalObject_01() .run(this); 391 new EADeoptFrameAfterReadLocalObject_01B() .run(this); 392 new EADeoptFrameAfterReadLocalObject_02() .run(this); 393 new EADeoptFrameAfterReadLocalObject_02B() .run(this); 394 new EADeoptFrameAfterReadLocalObject_02C() .run(this); 395 new EADeoptFrameAfterReadLocalObject_03() .run(this); 396 397 // PopFrame test cases 398 new EAPopFrameNotInlined() .run(this); 399 new EAPopFrameNotInlinedReallocFailure() .run(this); 400 new EAPopInlinedMethodWithScalarReplacedObjectsReallocFailure() .run(this); 401 402 // ForceEarlyReturn test cases 403 new EAForceEarlyReturnNotInlined() .run(this); 404 new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjects() .run(this); 405 new EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailure().run(this); 406 407 // Instances of ReferenceType 408 new EAGetInstancesOfReferenceType() .run(this); 409 410 // resume the target listening for events 411 listenUntilVMDisconnect(); 412 } 413 414 // Print a Message 415 public void msg(String m) { 416 System.out.println(); 417 System.out.println("###(Debugger) " + m); 418 System.out.println(); 419 } 420 421 // Highlighted message. 422 public void msgHL(String m) { 423 System.out.println(); 424 System.out.println(); 425 System.out.println("##########################################################"); 426 System.out.println("### " + m); 427 System.out.println("### "); 428 System.out.println(); 429 System.out.println(); 430 } 431 } 432 433 ///////////////////////////////////////////////////////////////////////////// 434 // 435 // Base class for debugger side of test cases. 436 // 437 ///////////////////////////////////////////////////////////////////////////// 438 439 abstract class EATestCaseBaseDebugger extends EATestCaseBaseShared { 440 441 protected EATests env; 442 443 public ObjectReference testCase; 444 445 public static final String TARGET_TESTCASE_BASE_NAME = EATestCaseBaseTarget.class.getName(); 446 447 public static final String XYVAL_NAME = XYVal.class.getName(); 448 449 public abstract void runTestCase() throws Exception; 450 451 @Override 452 public boolean shouldSkip() { 453 // Skip if StressReflectiveCode because it effectively disables escape analysis 454 return super.shouldSkip() || env.targetVMOptions.StressReflectiveCode; 455 } 456 457 public void run(EATests env) { 458 this.env = env; 459 if (shouldSkip()) { 460 msg("skipping " + testCaseName); 461 return; 462 } 463 try { 464 msgHL("Executing test case " + getClass().getName()); 465 env.testFailed = false; 466 467 if (INTERACTIVE) 468 env.waitForInput(); 469 470 resumeToWarmupDone(); 471 runTestCase(); 472 Asserts.assertTrue(env.targetMainThread.isSuspended(), "must be suspended after the testcase"); 473 resumeToTestCaseDone(); 474 checkPostConditions(); 475 } catch (Exception e) { 476 Asserts.fail("Unexpected exception in test case " + getClass().getName(), e); 477 } 478 } 479 480 /** 481 * Set a breakpoint in the given method and resume all threads. The 482 * breakpoint is configured to suspend just the thread that reaches it 483 * instead of all threads. This is important when running with graal. 484 */ 485 public BreakpointEvent resumeTo(String clsName, String methodName, String signature) { 486 boolean suspendThreadOnly = true; 487 return env.resumeTo(clsName, methodName, signature, suspendThreadOnly); 488 } 489 490 public void resumeToWarmupDone() throws Exception { 491 msg("resuming to " + TARGET_TESTCASE_BASE_NAME + ".warmupDone()V"); 492 resumeTo(TARGET_TESTCASE_BASE_NAME, "warmupDone", "()V"); 493 testCase = env.targetMainThread.frame(0).thisObject(); 494 } 495 496 public void resumeToTestCaseDone() { 497 msg("resuming to " + TARGET_TESTCASE_BASE_NAME + ".testCaseDone()V"); 498 resumeTo(TARGET_TESTCASE_BASE_NAME, "testCaseDone", "()V"); 499 } 500 501 public void checkPostConditions() throws Exception { 502 Asserts.assertFalse(env.getExceptionCaught(), "Uncaught exception in Debuggee"); 503 504 String testName = getClass().getName(); 505 if (!env.testFailed) { 506 env.println(testName + ": passed"); 507 } else { 508 throw new Exception(testName + ": failed"); 509 } 510 } 511 512 public void printStack(ThreadReference thread) throws Exception { 513 msg("Debuggee Stack:"); 514 List<StackFrame> stack_frames = thread.frames(); 515 int i = 0; 516 for (StackFrame ff : stack_frames) { 517 System.out.println("frame[" + i++ +"]: " + ff.location().method() + " (bci:" + ff.location().codeIndex() + ")"); 518 } 519 } 520 521 public void msg(String m) { 522 env.msg(m); 523 } 524 525 public void msgHL(String m) { 526 env.msgHL(m); 527 } 528 529 // See Field Descriptors in The Java Virtual Machine Specification 530 // (https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.3.2) 531 enum FD { 532 I, // int 533 J, // long 534 F, // float 535 D, // double 536 } 537 538 // Map field descriptor to jdi type string 539 public static final Map<FD, String> FD2JDIArrType = Map.of(FD.I, "int[]", FD.J, "long[]", FD.F, "float[]", FD.D, "double[]"); 540 541 // Map field descriptor to PrimitiveValue getter 542 public static final Function<PrimitiveValue, Integer> v2I = PrimitiveValue::intValue; 543 public static final Function<PrimitiveValue, Long> v2J = PrimitiveValue::longValue; 544 public static final Function<PrimitiveValue, Float> v2F = PrimitiveValue::floatValue; 545 public static final Function<PrimitiveValue, Double> v2D = PrimitiveValue::doubleValue; 546 Map<FD, Function<PrimitiveValue, ?>> FD2getter = Map.of(FD.I, v2I, FD.J, v2J, FD.F, v2F, FD.D, v2D); 547 548 /** 549 * Retrieve array of primitive values referenced by a local variable in target and compare with 550 * an array of expected values. 551 * @param frame Frame in the target holding the local variable 552 * @param lName Name of the local variable referencing the array to be retrieved 553 * @param desc Array element type given as field descriptor. 554 * @param expVals Array of expected values. 555 * @throws Exception 556 */ 557 protected void checkLocalPrimitiveArray(StackFrame frame, String lName, FD desc, Object expVals) throws Exception { 558 String lType = FD2JDIArrType.get(desc); 559 Asserts.assertNotNull(lType, "jdi type not found"); 560 Asserts.assertEQ(EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, frame .location().method().name()); 561 List<LocalVariable> localVars = frame.visibleVariables(); 562 msg("Check if the local array variable '" + lName + "' in " + EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME + " has the expected elements: "); 563 boolean found = false; 564 for (LocalVariable lv : localVars) { 565 if (lv.name().equals(lName)) { 566 found = true; 567 Value lVal = frame.getValue(lv); 568 Asserts.assertNotNull(lVal); 569 Asserts.assertEQ(lVal.type().name(), lType); 570 ArrayReference aRef = (ArrayReference) lVal; 571 Asserts.assertEQ(3, aRef.length()); 572 // now check the elements 573 for (int i = 0; i < aRef.length(); i++) { 574 Object actVal = FD2getter.get(desc).apply((PrimitiveValue)aRef.getValue(i)); 575 Object expVal = Array.get(expVals, i); 576 Asserts.assertEQ(expVal, actVal, "checking element at index " + i); 577 } 578 } 579 } 580 Asserts.assertTrue(found); 581 msg("OK."); 582 } 583 584 /** 585 * Retrieve array of objects referenced by a local variable in target and compare with an array 586 * of expected values. 587 * @param frame Frame in the target holding the local variable 588 * @param lName Name of the local variable referencing the array to be retrieved 589 * @param lType Local type, e.g. java.lang.Long[] 590 * @param expVals Array of expected values. 591 * @throws Exception 592 */ 593 protected void checkLocalObjectArray(StackFrame frame, String lName, String lType, ObjectReference[] expVals) throws Exception { 594 Asserts.assertEQ(EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, frame .location().method().name()); 595 List<LocalVariable> localVars = frame.visibleVariables(); 596 msg("Check if the local array variable '" + lName + "' in " + EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME + " has the expected elements: "); 597 boolean found = false; 598 for (LocalVariable lv : localVars) { 599 if (lv.name().equals(lName)) { 600 found = true; 601 Value lVal = frame.getValue(lv); 602 Asserts.assertNotNull(lVal); 603 Asserts.assertEQ(lType, lVal.type().name()); 604 ArrayReference aRef = (ArrayReference) lVal; 605 Asserts.assertEQ(3, aRef.length()); 606 // now check the elements 607 for (int i = 0; i < aRef.length(); i++) { 608 ObjectReference actVal = (ObjectReference)aRef.getValue(i); 609 Asserts.assertSame(expVals[i], actVal, "checking element at index " + i); 610 } 611 } 612 } 613 Asserts.assertTrue(found); 614 msg("OK."); 615 } 616 617 /** 618 * Retrieve a reference held by a local variable in the given frame. Check if the frame's method 619 * is the expected method if the retrieved local value has the expected type and is not null. 620 * @param frame The frame to retrieve the local variable value from. 621 * @param expectedMethodName The name of the frames method should match the expectedMethodName. 622 * @param lName The name of the local variable which is read. 623 * @param expectedType Is the expected type of the object referenced by the local variable. 624 * @return 625 * @throws Exception 626 */ 627 protected ObjectReference getLocalRef(StackFrame frame, String expectedMethodName, String lName, String expectedType) throws Exception { 628 Asserts.assertEQ(expectedMethodName, frame.location().method().name()); 629 List<LocalVariable> localVars = frame.visibleVariables(); 630 msg("Get and check local variable '" + lName + "' in " + expectedMethodName); 631 ObjectReference lRef = null; 632 for (LocalVariable lv : localVars) { 633 if (lv.name().equals(lName)) { 634 Value lVal = frame.getValue(lv); 635 Asserts.assertNotNull(lVal); 636 Asserts.assertEQ(expectedType, lVal.type().name()); 637 lRef = (ObjectReference) lVal; 638 break; 639 } 640 } 641 Asserts.assertNotNull(lRef, "Local variable '" + lName + "' not found"); 642 msg("OK."); 643 return lRef; 644 } 645 646 /** 647 * Retrieve a reference held by a local variable in the given frame. Check if the frame's method 648 * matches {@link EATestCaseBaseTarget#TESTMETHOD_DEFAULT_NAME} if the retrieved local value has 649 * the expected type and is not null. 650 * @param frame The frame to retrieve the local variable value from. 651 * @param expectedMethodName The name of the frames method should match the expectedMethodName. 652 * @param lName The name of the local variable which is read. 653 * @param expectedType Is the expected type of the object referenced by the local variable. 654 * @return 655 * @throws Exception 656 */ 657 protected ObjectReference getLocalRef(StackFrame frame, String lType, String lName) throws Exception { 658 return getLocalRef(frame, EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, lName, lType); 659 } 660 661 /** 662 * Set the value of a local variable in the given frame. Check if the frame's method is the expected method. 663 * @param frame The frame holding the local variable. 664 * @param expectedMethodName The expected name of the frame's method. 665 * @param lName The name of the local variable to change. 666 * @param val The new value of the local variable. 667 * @throws Exception 668 */ 669 public void setLocal(StackFrame frame, String expectedMethodName, String lName, Value val) throws Exception { 670 Asserts.assertEQ(expectedMethodName, frame.location().method().name()); 671 List<LocalVariable> localVars = frame.visibleVariables(); 672 msg("Set local variable '" + lName + "' = " + val + " in " + expectedMethodName); 673 for (LocalVariable lv : localVars) { 674 if (lv.name().equals(lName)) { 675 frame.setValue(lv, val); 676 break; 677 } 678 } 679 msg("OK."); 680 } 681 682 /** 683 * Set the value of a local variable in the given frame. Check if the frame's method matches 684 * {@link EATestCaseBaseTarget#TESTMETHOD_DEFAULT_NAME}. 685 * @param frame The frame holding the local variable. 686 * @param expectedMethodName The expected name of the frame's method. 687 * @param lName The name of the local variable to change. 688 * @param val The new value of the local variable. 689 * @throws Exception 690 */ 691 public void setLocal(StackFrame frame, String lName, Value val) throws Exception { 692 setLocal(frame, EATestCaseBaseTarget.TESTMETHOD_DEFAULT_NAME, lName, val); 693 } 694 695 /** 696 * Check if a field has the expected primitive value. 697 * @param o Object holding the field. 698 * @param desc Field descriptor. 699 * @param fName Field name 700 * @param expVal Expected primitive value 701 * @throws Exception 702 */ 703 protected void checkPrimitiveField(ObjectReference o, FD desc, String fName, Object expVal) throws Exception { 704 msg("check field " + fName); 705 ReferenceType rt = o.referenceType(); 706 Field fld = rt.fieldByName(fName); 707 Value val = o.getValue(fld); 708 Object actVal = FD2getter.get(desc).apply((PrimitiveValue) val); 709 Asserts.assertEQ(expVal, actVal, "field '" + fName + "' has unexpected value."); 710 msg("ok"); 711 } 712 713 /** 714 * Check if a field references the expected object. 715 * @param obj Object holding the field. 716 * @param fName Field name 717 * @param expVal Object expected to be referenced by the field 718 * @throws Exception 719 */ 720 protected void checkObjField(ObjectReference obj, String fName, ObjectReference expVal) throws Exception { 721 msg("check field " + fName); 722 ReferenceType rt = obj.referenceType(); 723 Field fld = rt.fieldByName(fName); 724 Value actVal = obj.getValue(fld); 725 Asserts.assertEQ(expVal, actVal, "field '" + fName + "' has unexpected value."); 726 msg("ok"); 727 } 728 729 protected void setField(ObjectReference obj, String fName, Value val) throws Exception { 730 msg("set field " + fName + " = " + val); 731 ReferenceType rt = obj.referenceType(); 732 Field fld = rt.fieldByName(fName); 733 obj.setValue(fld, val); 734 msg("ok"); 735 } 736 737 protected Value getField(ObjectReference obj, String fName) throws Exception { 738 msg("get field " + fName); 739 ReferenceType rt = obj.referenceType(); 740 Field fld = rt.fieldByName(fName); 741 Value val = obj.getValue(fld); 742 msg("result : " + val); 743 return val; 744 } 745 746 /** 747 * Free the memory consumed in the target by {@link EATestCaseBaseTarget#consumedMemory} 748 * @throws Exception 749 */ 750 public void freeAllMemory() throws Exception { 751 msg("free consumed memory"); 752 setField(testCase, "consumedMemory", null); 753 } 754 755 /** 756 * @return The value of {@link EATestCaseBaseTarget#targetIsInLoop}. The target must set that field to true as soon as it 757 * enters the endless loop. 758 * @throws Exception 759 */ 760 public boolean targetHasEnteredEndlessLoop() throws Exception { 761 Value v = getField(testCase, "targetIsInLoop"); 762 return ((PrimitiveValue) v).booleanValue(); 763 } 764 765 /** 766 * Poll {@link EATestCaseBaseTarget#targetIsInLoop} and return if it is found to be true. 767 * @throws Exception 768 */ 769 public void waitUntilTargetHasEnteredEndlessLoop() throws Exception { 770 while(!targetHasEnteredEndlessLoop()) { 771 msg("Target has not yet entered the loop. Sleep 200ms."); 772 try { Thread.sleep(200); } catch (InterruptedException e) { /*ignore */ } 773 } 774 } 775 776 /** 777 * Set {@link EATestCaseBaseTarget#doLoop} to <code>false</code>. This will allow the target to 778 * leave the endless loop. 779 * @throws Exception 780 */ 781 public void terminateEndlessLoop() throws Exception { 782 msg("terminate loop"); 783 setField(testCase, "doLoop", env.vm().mirrorOf(false)); 784 } 785 } 786 787 ///////////////////////////////////////////////////////////////////////////// 788 // 789 // Base class for debuggee side of test cases. 790 // 791 ///////////////////////////////////////////////////////////////////////////// 792 793 abstract class EATestCaseBaseTarget extends EATestCaseBaseShared implements Runnable { 794 795 /** 796 * The target must set that field to true as soon as it enters the endless loop. 797 */ 798 public volatile boolean targetIsInLoop; 799 800 /** 801 * Used for busy loops. See {@link #dontinline_endlessLoop()}. 802 */ 803 public volatile long loopCount; 804 805 /** 806 * Used in {@link EATestCaseBaseDebugger#terminateEndlessLoop()} to signal target to leave the endless loop. 807 */ 808 public volatile boolean doLoop; 809 810 public long checkSum; 811 812 public static final String TESTMETHOD_DEFAULT_NAME = "dontinline_testMethod"; 813 814 public static final WhiteBox WB = WhiteBox.getWhiteBox(); 815 816 public static boolean unbox(Boolean value, boolean dflt) { 817 return value == null ? dflt : value; 818 } 819 820 // Some of the fields are only read by the debugger 821 public static final boolean UseJVMCICompiler = unbox(WB.getBooleanVMFlag("UseJVMCICompiler"), false); 822 public static final boolean DoEscapeAnalysis = unbox(WB.getBooleanVMFlag("DoEscapeAnalysis"), UseJVMCICompiler); 823 public static final boolean EliminateAllocations = unbox(WB.getBooleanVMFlag("EliminateAllocations"), UseJVMCICompiler); 824 public static final boolean DeoptimizeObjectsALot = WB.getBooleanVMFlag("DeoptimizeObjectsALot"); 825 public static final boolean ZGCIsSelected = GC.Z.isSelected(); 826 public static final boolean ShenandoahGCIsSelected = GC.Shenandoah.isSelected(); 827 public static final boolean StressReflectiveCode = unbox(WB.getBooleanVMFlag("StressReflectiveCode"), false); 828 829 public String testMethodName; 830 public int testMethodDepth; 831 832 // Results produced by dontinline_testMethod() 833 public int iResult; 834 public long lResult; 835 public float fResult; 836 public double dResult; 837 838 839 public boolean warmupDone; 840 841 // an object with an inflated monitor 842 public static XYVal inflatedLock; 843 public static Thread inflatorThread; 844 public static boolean inflatedLockIsPermanentlyInflated; 845 846 public static int NOT_CONST_1I = 1; 847 public static long NOT_CONST_1L = 1L; 848 public static float NOT_CONST_1F = 1.1F; 849 public static double NOT_CONST_1D = 1.1D; 850 851 public static Long NOT_CONST_1_OBJ = Long.valueOf(1); 852 853 854 public static final Long CONST_2_OBJ = Long.valueOf(2); 855 public static final Long CONST_3_OBJ = Long.valueOf(3); 856 857 @Override 858 public boolean shouldSkip() { 859 // Skip if StressReflectiveCode because it effectively disables escape analysis 860 return super.shouldSkip() || StressReflectiveCode; 861 } 862 863 /** 864 * Main driver of a test case. 865 * <ul> 866 * <li> Skips test case if not selected (see {@link EATestCaseBaseShared#RUN_ONLY_TEST_CASE} 867 * <li> Call {@link #setUp()} 868 * <li> warm-up and compile {@link #dontinline_testMethod()} (see {@link #compileTestMethod()} 869 * <li> calling {@link #dontinline_testMethod()} 870 * <li> checking the result (see {@link #checkResult()} 871 * <ul> 872 */ 873 public void run() { 874 try { 875 if (shouldSkip()) { 876 msg("skipping " + testCaseName); 877 return; 878 } 879 setUp(); 880 msg(testCaseName + " is up and running."); 881 compileTestMethod(); 882 msg(testCaseName + " warmup done."); 883 warmupDone(); 884 checkCompLevel(); 885 dontinline_testMethod(); 886 checkResult(); 887 msg(testCaseName + " done."); 888 testCaseDone(); 889 } catch (Exception e) { 890 Asserts.fail("Caught unexpected exception", e); 891 } 892 } 893 894 public static void staticSetUp() { 895 inflatedLock = new XYVal(1, 1); 896 synchronized (inflatedLock) { 897 inflatorThread = DebuggeeWrapper.newThread(() -> { 898 synchronized (inflatedLock) { 899 inflatedLockIsPermanentlyInflated = true; 900 inflatedLock.notify(); // main thread 901 while (true) { 902 try { 903 // calling wait() on a monitor will cause inflation into a heavy monitor 904 inflatedLock.wait(); 905 } catch (InterruptedException e) { /* ignored */ } 906 } 907 } 908 }, "Lock Inflator (test thread)"); 909 inflatorThread.setDaemon(true); 910 inflatorThread.start(); 911 912 // wait until the lock is permanently inflated by the inflatorThread 913 while(!inflatedLockIsPermanentlyInflated) { 914 try { 915 inflatedLock.wait(); // until inflated 916 } catch (InterruptedException e1) { /* ignored */ } 917 } 918 } 919 } 920 921 // Debugger will set breakpoint here to sync with target. 922 public static void staticSetUpDone() { 923 } 924 925 public void setUp() { 926 testMethodDepth = 1; 927 testMethodName = TESTMETHOD_DEFAULT_NAME; 928 } 929 930 public abstract void dontinline_testMethod() throws Exception; 931 932 public int dontinline_brkpt_iret() { 933 dontinline_brkpt(); 934 return 42; 935 } 936 937 /** 938 * It is a common protocol to have the debugger set a breakpoint in this method and have {@link 939 * #dontinline_testMethod()} call it and then perform some test actions on debugger side. 940 * After that it is checked if a frame of {@link #dontinline_testMethod()} is found at the 941 * expected depth on stack and if it is (not) marked for deoptimization as expected. 942 */ 943 public void dontinline_brkpt() { 944 // will set breakpoint here after warmup 945 if (warmupDone) { 946 // check if test method is at expected depth 947 StackTraceElement[] frames = Thread.currentThread().getStackTrace(); 948 int stackTraceDepth = testMethodDepth + 1; // ignore java.lang.Thread.getStackTrace() 949 Asserts.assertEQ(testMethodName, frames[stackTraceDepth].getMethodName(), 950 testCaseName + ": test method not found at depth " + testMethodDepth); 951 // check if the frame is (not) deoptimized as expected 952 if (!DeoptimizeObjectsALot) { 953 if (testFrameShouldBeDeoptimized()) { 954 Asserts.assertTrue(WB.isFrameDeoptimized(testMethodDepth+1), 955 testCaseName + ": expected test method frame at depth " + testMethodDepth + " to be deoptimized"); 956 } else { 957 Asserts.assertFalse(WB.isFrameDeoptimized(testMethodDepth+1), 958 testCaseName + ": expected test method frame at depth " + testMethodDepth + " not to be deoptimized"); 959 } 960 } 961 } 962 } 963 964 /** 965 * Some test cases run busy endless loops by initializing {@link #loopCount} 966 * to {@link Long#MAX_VALUE} after warm-up and then counting down to 0 in their main test method. 967 * During warm-up {@link #loopCount} is initialized to a small value. 968 */ 969 public long dontinline_endlessLoop() { 970 long cs = checkSum; 971 doLoop = true; 972 while (loopCount-- > 0 && doLoop) { 973 targetIsInLoop = true; 974 checkSum += checkSum % ++cs; 975 } 976 loopCount = 3; 977 targetIsInLoop = false; 978 return checkSum; 979 } 980 981 public boolean testFrameShouldBeDeoptimized() { 982 return DoEscapeAnalysis; 983 } 984 985 public void warmupDone() { 986 warmupDone = true; 987 } 988 989 // Debugger will set breakpoint here to sync with target. 990 public void testCaseDone() { 991 } 992 993 public void compileTestMethod() throws Exception { 994 int callCount = CompilerWhiteBoxTest.THRESHOLD; 995 while (callCount-- > 0) { 996 dontinline_testMethod(); 997 } 998 } 999 1000 public void checkCompLevel() { 1001 java.lang.reflect.Method m = null; 1002 try { 1003 m = getClass().getMethod(TESTMETHOD_DEFAULT_NAME); 1004 } catch (NoSuchMethodException | SecurityException e) { 1005 Asserts.fail("could not check compilation level of", e); 1006 } 1007 int highestLevel = CompilerUtils.getMaxCompilationLevel(); 1008 int compLevel = WB.getMethodCompilationLevel(m); 1009 if (!UseJVMCICompiler) { 1010 Asserts.assertEQ(highestLevel, compLevel, 1011 m + " not on expected compilation level"); 1012 } else { 1013 // Background compilation (-Xbatch) will block a thread with timeout 1014 // (see CompileBroker::wait_for_jvmci_completion()). Therefore it is 1015 // possible to reach here before the main test method is compiled. 1016 // In that case we wait for it to be compiled. 1017 while (compLevel != highestLevel) { 1018 msg(TESTMETHOD_DEFAULT_NAME + " is compiled on level " + compLevel + 1019 ". Wait until highes level (" + highestLevel + ") is reached."); 1020 try { 1021 Thread.sleep(200); 1022 } catch (InterruptedException e) { /* ignored */ } 1023 compLevel = WB.getMethodCompilationLevel(m); 1024 } 1025 } 1026 } 1027 1028 // to be overridden as appropriate 1029 public int getExpectedIResult() { 1030 return 0; 1031 } 1032 1033 // to be overridden as appropriate 1034 public long getExpectedLResult() { 1035 return 0; 1036 } 1037 1038 // to be overridden as appropriate 1039 public float getExpectedFResult() { 1040 return 0f; 1041 } 1042 1043 // to be overridden as appropriate 1044 public double getExpectedDResult() { 1045 return 0d; 1046 } 1047 1048 private void checkResult() { 1049 Asserts.assertEQ(getExpectedIResult(), iResult, "checking iResult"); 1050 Asserts.assertEQ(getExpectedLResult(), lResult, "checking lResult"); 1051 Asserts.assertEQ(getExpectedFResult(), fResult, "checking fResult"); 1052 Asserts.assertEQ(getExpectedDResult(), dResult, "checking dResult"); 1053 } 1054 1055 public void msg(String m) { 1056 System.out.println(); 1057 System.out.println("###(Target) " + m); 1058 System.out.println(); 1059 } 1060 1061 // The object passed will be ArgEscape if it was NoEscape before. 1062 public final void dontinline_make_arg_escape(XYVal xy) { 1063 } 1064 1065 /** 1066 * Call a method indirectly using reflection. The indirection is a limit for escape 1067 * analysis in the sense that the VM need not search beyond for frames that might have 1068 * an object being read by an JVMTI agent as ArgEscape. 1069 * @param receiver The receiver object of the call. 1070 * @param methodName The name of the method to be called. 1071 */ 1072 public final void dontinline_call_with_entry_frame(Object receiver, String methodName) { 1073 Asserts.assertTrue(warmupDone, "We want to take the slow path through jni, so don't call in warmup"); 1074 1075 Class<?> cls = receiver.getClass(); 1076 Class<?>[] none = {}; 1077 1078 java.lang.reflect.Method m; 1079 try { 1080 m = cls.getDeclaredMethod(methodName, none); 1081 m.invoke(receiver); 1082 } catch (Exception e) { 1083 Asserts.fail("Call through reflection failed", e); 1084 } 1085 } 1086 1087 static class LinkedList { 1088 LinkedList l; 1089 public long[] array; 1090 public LinkedList(LinkedList l, int size) { 1091 this.array = size > 0 ? new long[size] : null; 1092 this.l = l; 1093 } 1094 } 1095 1096 public LinkedList consumedMemory; 1097 1098 public void consumeAllMemory() { 1099 msg("consume all memory"); 1100 int size = 128 * 1024 * 1024; 1101 while(true) { 1102 try { 1103 while(true) { 1104 consumedMemory = new LinkedList(consumedMemory, size); 1105 } 1106 } catch(OutOfMemoryError oom) { 1107 if (size == 0) break; 1108 } 1109 size = size / 2; 1110 } 1111 } 1112 } 1113 1114 ///////////////////////////////////////////////////////////////////////////// 1115 // 1116 // Test Cases 1117 // 1118 ///////////////////////////////////////////////////////////////////////////// 1119 1120 // make sure a compiled frame is not deoptimized if an escaping local is accessed 1121 class EAGetWithoutMaterializeTarget extends EATestCaseBaseTarget { 1122 1123 public XYVal getAway; 1124 1125 public void dontinline_testMethod() { 1126 XYVal xy = new XYVal(4, 2); 1127 getAway = xy; // allocated object escapes 1128 dontinline_brkpt(); 1129 iResult = xy.x + xy.y; 1130 } 1131 1132 @Override 1133 public int getExpectedIResult() { 1134 return 4 + 2; 1135 } 1136 1137 @Override 1138 public boolean testFrameShouldBeDeoptimized() { 1139 return false; 1140 } 1141 } 1142 1143 class EAGetWithoutMaterialize extends EATestCaseBaseDebugger { 1144 1145 public void runTestCase() throws Exception { 1146 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1147 printStack(bpe.thread()); 1148 ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy"); 1149 checkPrimitiveField(o, FD.I, "x", 4); 1150 checkPrimitiveField(o, FD.I, "y", 2); 1151 } 1152 } 1153 1154 ///////////////////////////////////////////////////////////////////////////// 1155 1156 // 1157 // Tests the following: 1158 // 1159 // 1. Debugger can obtain a reference to a scalar replaced object R from java thread J. 1160 // See runTestCase. 1161 // 1162 // 2. Subsequent modifications of R by J are noticed by the debugger. 1163 // See checkPostConditions. 1164 // 1165 class EAMaterializeLocalVariableUponGet extends EATestCaseBaseDebugger { 1166 1167 private ObjectReference o; 1168 1169 public void runTestCase() throws Exception { 1170 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1171 printStack(bpe.thread()); 1172 // check 1. 1173 o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy"); 1174 // o is referenced in checkPostConditions() and must not be gc'ed. 1175 o.disableCollection(); 1176 checkPrimitiveField(o, FD.I, "x", 4); 1177 checkPrimitiveField(o, FD.I, "y", 2); 1178 } 1179 1180 @Override 1181 public void checkPostConditions() throws Exception { 1182 super.checkPostConditions(); 1183 // check 2. 1184 checkPrimitiveField(o, FD.I, "x", 5); 1185 } 1186 } 1187 1188 class EAMaterializeLocalVariableUponGetTarget extends EATestCaseBaseTarget { 1189 1190 public void dontinline_testMethod() { 1191 XYVal xy = new XYVal(4, 2); 1192 dontinline_brkpt(); // Debugger obtains scalar replaced object at this point. 1193 xy.x += 1; // Change scalar replaced object after debugger obtained a reference to it. 1194 iResult = xy.x + xy.y; 1195 } 1196 1197 @Override 1198 public int getExpectedIResult() { 1199 return 4 + 2 + 1; 1200 } 1201 } 1202 1203 ///////////////////////////////////////////////////////////////////////////// 1204 1205 // Test if an eliminated object can be reallocated in a frame with an active 1206 // call that will return another object 1207 class EAMaterializeLocalAtObjectReturn extends EATestCaseBaseDebugger { 1208 public void runTestCase() throws Exception { 1209 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1210 printStack(bpe.thread()); 1211 ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "xy"); 1212 checkPrimitiveField(o, FD.I, "x", 4); 1213 checkPrimitiveField(o, FD.I, "y", 2); 1214 } 1215 } 1216 1217 class EAMaterializeLocalAtObjectReturnTarget extends EATestCaseBaseTarget { 1218 @Override 1219 public void setUp() { 1220 super.setUp(); 1221 testMethodDepth = 2; 1222 } 1223 1224 public void dontinline_testMethod() { 1225 XYVal xy = new XYVal(4, 2); 1226 Integer io = // Read xy here triggers reallocation 1227 dontinline_brkpt_return_Integer(); 1228 iResult = xy.x + xy.y + io; 1229 } 1230 1231 public Integer dontinline_brkpt_return_Integer() { 1232 // We can't break directly in this method, as this results in making 1233 // the test method not entrant caused by an existing dependency 1234 dontinline_brkpt(); 1235 return Integer.valueOf(23); 1236 } 1237 1238 @Override 1239 public int getExpectedIResult() { 1240 return 4 + 2 + 23; 1241 } 1242 } 1243 1244 ///////////////////////////////////////////////////////////////////////////// 1245 1246 // Test if an eliminated object can be reallocated *just* before a call returns an object. 1247 // (See CompiledMethod::is_at_poll_return()) 1248 // Details: the callee method has just one safepoint poll at the return. The other safepoint 1249 // is at the end of an iteration of the endless loop. We can detect if we suspended the target 1250 // there because the local xy is out of scope there. 1251 class EAMaterializeLocalAtObjectPollReturnReturn extends EATestCaseBaseDebugger { 1252 public void runTestCase() throws Exception { 1253 msg("Resume " + env.targetMainThread); 1254 env.vm().resume(); 1255 waitUntilTargetHasEnteredEndlessLoop(); 1256 ObjectReference o = null; 1257 int retryCount = 0; 1258 do { 1259 env.targetMainThread.suspend(); 1260 printStack(env.targetMainThread); 1261 try { 1262 o = getLocalRef(env.targetMainThread.frame(0), XYVAL_NAME, "xy"); 1263 } catch (Exception e) { 1264 ++retryCount; 1265 msg("The local variable xy is out of scope because we suspended at the wrong bci. Resume and try again! (" + retryCount + ")"); 1266 env.targetMainThread.resume(); 1267 if ((retryCount % 10) == 0) { 1268 Thread.sleep(200); 1269 } 1270 } 1271 } while (o == null); 1272 checkPrimitiveField(o, FD.I, "x", 4); 1273 checkPrimitiveField(o, FD.I, "y", 2); 1274 terminateEndlessLoop(); 1275 } 1276 } 1277 1278 class EAMaterializeLocalAtObjectPollReturnReturnTarget extends EATestCaseBaseTarget { 1279 @Override 1280 public void setUp() { 1281 super.setUp(); 1282 loopCount = 3; 1283 doLoop = true; 1284 } 1285 1286 public void warmupDone() { 1287 super.warmupDone(); 1288 msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE"); 1289 loopCount = Long.MAX_VALUE; // endless loop 1290 } 1291 1292 public void dontinline_testMethod() { 1293 long result = 0; 1294 while (doLoop && loopCount-- > 0) { 1295 targetIsInLoop = true; 1296 XYVal xy = new XYVal(4, 2); 1297 Integer io = // Read xy here triggers reallocation just before the call returns 1298 dontinline_brkpt_return_Integer(); 1299 result += xy.x + xy.y + io; 1300 } // Here is a second safepoint. We were suspended here if xy is not in scope. 1301 targetIsInLoop = false; 1302 lResult = result; 1303 } 1304 1305 public Integer dontinline_brkpt_return_Integer() { 1306 return Integer.valueOf(23); 1307 } 1308 1309 @Override 1310 public long getExpectedLResult() { 1311 return (Long.MAX_VALUE - loopCount) * (4+2+23); 1312 } 1313 } 1314 1315 ///////////////////////////////////////////////////////////////////////////// 1316 // Test case collection that tests rematerialization of different 1317 // array types where the first element is always not constant and the 1318 // other elements are constants. Not constant values are stored in 1319 // the stack frame for rematerialization whereas constants are kept 1320 // in the debug info of the nmethod. 1321 1322 class EAMaterializeIntArrayTarget extends EATestCaseBaseTarget { 1323 1324 public void dontinline_testMethod() { 1325 int nums[] = {NOT_CONST_1I , 2, 3}; 1326 dontinline_brkpt(); 1327 iResult = nums[0] + nums[1] + nums[2]; 1328 } 1329 1330 @Override 1331 public int getExpectedIResult() { 1332 return NOT_CONST_1I + 2 + 3; 1333 } 1334 } 1335 1336 class EAMaterializeIntArray extends EATestCaseBaseDebugger { 1337 public void runTestCase() throws Exception { 1338 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1339 printStack(bpe.thread()); 1340 int[] expectedVals = {1, 2, 3}; 1341 checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.I, expectedVals); 1342 } 1343 } 1344 1345 ///////////////////////////////////////////////////////////////////////////// 1346 1347 class EAMaterializeLongArrayTarget extends EATestCaseBaseTarget { 1348 1349 public void dontinline_testMethod() { 1350 long nums[] = {NOT_CONST_1L , 2, 3}; 1351 dontinline_brkpt(); 1352 lResult = nums[0] + nums[1] + nums[2]; 1353 } 1354 1355 @Override 1356 public long getExpectedLResult() { 1357 return NOT_CONST_1L + 2 + 3; 1358 } 1359 } 1360 1361 class EAMaterializeLongArray extends EATestCaseBaseDebugger { 1362 public void runTestCase() throws Exception { 1363 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1364 printStack(bpe.thread()); 1365 long[] expectedVals = {1, 2, 3}; 1366 checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.J, expectedVals); 1367 } 1368 } 1369 1370 ///////////////////////////////////////////////////////////////////////////// 1371 1372 class EAMaterializeFloatArrayTarget extends EATestCaseBaseTarget { 1373 1374 public void dontinline_testMethod() { 1375 float nums[] = {NOT_CONST_1F , 2.2f, 3.3f}; 1376 dontinline_brkpt(); 1377 fResult = nums[0] + nums[1] + nums[2]; 1378 } 1379 1380 @Override 1381 public float getExpectedFResult() { 1382 return NOT_CONST_1F + 2.2f + 3.3f; 1383 } 1384 } 1385 1386 class EAMaterializeFloatArray extends EATestCaseBaseDebugger { 1387 public void runTestCase() throws Exception { 1388 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1389 printStack(bpe.thread()); 1390 float[] expectedVals = {1.1f, 2.2f, 3.3f}; 1391 checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.F, expectedVals); 1392 } 1393 } 1394 1395 ///////////////////////////////////////////////////////////////////////////// 1396 1397 class EAMaterializeDoubleArrayTarget extends EATestCaseBaseTarget { 1398 1399 public void dontinline_testMethod() { 1400 double nums[] = {NOT_CONST_1D , 2.2d, 3.3d}; 1401 dontinline_brkpt(); 1402 dResult = nums[0] + nums[1] + nums[2]; 1403 } 1404 1405 @Override 1406 public double getExpectedDResult() { 1407 return NOT_CONST_1D + 2.2d + 3.3d; 1408 } 1409 } 1410 1411 class EAMaterializeDoubleArray extends EATestCaseBaseDebugger { 1412 public void runTestCase() throws Exception { 1413 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1414 printStack(bpe.thread()); 1415 double[] expectedVals = {1.1d, 2.2d, 3.3d}; 1416 checkLocalPrimitiveArray(bpe.thread().frame(1), "nums", FD.D, expectedVals); 1417 } 1418 } 1419 1420 ///////////////////////////////////////////////////////////////////////////// 1421 1422 class EAMaterializeObjectArrayTarget extends EATestCaseBaseTarget { 1423 1424 public void dontinline_testMethod() { 1425 Long nums[] = {NOT_CONST_1_OBJ , CONST_2_OBJ, CONST_3_OBJ}; 1426 dontinline_brkpt(); 1427 lResult = nums[0] + nums[1] + nums[2]; 1428 } 1429 1430 @Override 1431 public long getExpectedLResult() { 1432 return 1 + 2 + 3; 1433 } 1434 } 1435 1436 class EAMaterializeObjectArray extends EATestCaseBaseDebugger { 1437 public void runTestCase() throws Exception { 1438 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1439 printStack(bpe.thread()); 1440 ReferenceType clazz = bpe.thread().frame(0).location().declaringType(); 1441 ObjectReference[] expectedVals = { 1442 (ObjectReference) clazz.getValue(clazz.fieldByName("NOT_CONST_1_OBJ")), 1443 (ObjectReference) clazz.getValue(clazz.fieldByName("CONST_2_OBJ")), 1444 (ObjectReference) clazz.getValue(clazz.fieldByName("CONST_3_OBJ")) 1445 }; 1446 checkLocalObjectArray(bpe.thread().frame(1), "nums", "java.lang.Long[]", expectedVals); 1447 } 1448 } 1449 1450 ///////////////////////////////////////////////////////////////////////////// 1451 1452 // Materialize an object whose fields have constant and not constant values at 1453 // the point where the object is materialized. 1454 class EAMaterializeObjectWithConstantAndNotConstantValuesTarget extends EATestCaseBaseTarget { 1455 1456 public void dontinline_testMethod() { 1457 ILFDO o = new ILFDO(NOT_CONST_1I, 2, 1458 NOT_CONST_1L, 2L, 1459 NOT_CONST_1F, 2.1F, 1460 NOT_CONST_1D, 2.1D, 1461 NOT_CONST_1_OBJ, CONST_2_OBJ 1462 ); 1463 dontinline_brkpt(); 1464 dResult = 1465 o.i + o.i2 + o.l + o.l2 + o.f + o.f2 + o.d + o.d2 + o.o + o.o2; 1466 } 1467 1468 @Override 1469 public double getExpectedDResult() { 1470 return NOT_CONST_1I + 2 + NOT_CONST_1L + 2L + NOT_CONST_1F + 2.1F + NOT_CONST_1D + 2.1D + NOT_CONST_1_OBJ + CONST_2_OBJ; 1471 } 1472 } 1473 1474 class EAMaterializeObjectWithConstantAndNotConstantValues extends EATestCaseBaseDebugger { 1475 public void runTestCase() throws Exception { 1476 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1477 printStack(bpe.thread()); 1478 ObjectReference o = getLocalRef(bpe.thread().frame(1), "ILFDO", "o"); 1479 checkPrimitiveField(o, FD.I, "i", 1); 1480 checkPrimitiveField(o, FD.I, "i2", 2); 1481 checkPrimitiveField(o, FD.J, "l", 1L); 1482 checkPrimitiveField(o, FD.J, "l2", 2L); 1483 checkPrimitiveField(o, FD.F, "f", 1.1f); 1484 checkPrimitiveField(o, FD.F, "f2", 2.1f); 1485 checkPrimitiveField(o, FD.D, "d", 1.1d); 1486 checkPrimitiveField(o, FD.D, "d2", 2.1d); 1487 ReferenceType clazz = bpe.thread().frame(1).location().declaringType(); 1488 ObjectReference[] expVals = { 1489 (ObjectReference) clazz.getValue(clazz.fieldByName("NOT_CONST_1_OBJ")), 1490 (ObjectReference) clazz.getValue(clazz.fieldByName("CONST_2_OBJ")), 1491 }; 1492 checkObjField(o, "o", expVals[0]); 1493 checkObjField(o, "o2", expVals[1]); 1494 } 1495 } 1496 1497 ///////////////////////////////////////////////////////////////////////////// 1498 1499 // Two local variables reference the same object. 1500 // Check if the debugger obtains the same object when reading the two variables 1501 class EAMaterializeObjReferencedBy2LocalsTarget extends EATestCaseBaseTarget { 1502 1503 public void dontinline_testMethod() { 1504 XYVal xy = new XYVal(2, 3); 1505 XYVal alias = xy; 1506 dontinline_brkpt(); 1507 iResult = xy.x + alias.x; 1508 } 1509 1510 @Override 1511 public int getExpectedIResult() { 1512 return 2 + 2; 1513 } 1514 } 1515 1516 class EAMaterializeObjReferencedBy2Locals extends EATestCaseBaseDebugger { 1517 1518 public void runTestCase() throws Exception { 1519 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1520 printStack(bpe.thread()); 1521 ObjectReference xy = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy"); 1522 ObjectReference alias = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "alias"); 1523 Asserts.assertSame(xy, alias, "xy and alias are expected to reference the same object"); 1524 } 1525 1526 } 1527 1528 ///////////////////////////////////////////////////////////////////////////// 1529 1530 // Two local variables reference the same object. 1531 // Check if it has the expected effect in the target if the debugger modifies the object. 1532 class EAMaterializeObjReferencedBy2LocalsAndModifyTarget extends EATestCaseBaseTarget { 1533 1534 public void dontinline_testMethod() { 1535 XYVal xy = new XYVal(2, 3); 1536 XYVal alias = xy; 1537 dontinline_brkpt(); // debugger: alias.x = 42 1538 iResult = xy.x + alias.x; 1539 } 1540 1541 @Override 1542 public int getExpectedIResult() { 1543 return 42 + 42; 1544 } 1545 } 1546 1547 class EAMaterializeObjReferencedBy2LocalsAndModify extends EATestCaseBaseDebugger { 1548 1549 public void runTestCase() throws Exception { 1550 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1551 printStack(bpe.thread()); 1552 ObjectReference alias = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "alias"); 1553 setField(alias, "x", env.vm().mirrorOf(42)); 1554 } 1555 } 1556 1557 ///////////////////////////////////////////////////////////////////////////// 1558 1559 // Two local variables of the same compiled frame but in different virtual frames reference the same 1560 // object. 1561 // Check if the debugger obtains the same object when reading the two variables 1562 class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesTarget extends EATestCaseBaseTarget { 1563 1564 @Override 1565 public void setUp() { 1566 super.setUp(); 1567 testMethodDepth = 2; 1568 } 1569 1570 public void dontinline_testMethod() { 1571 XYVal xy = new XYVal(2, 3); 1572 testMethod_inlined(xy); 1573 iResult += xy.x; 1574 } 1575 1576 public void testMethod_inlined(XYVal xy) { 1577 XYVal alias = xy; 1578 dontinline_brkpt(); 1579 iResult = alias.x; 1580 } 1581 1582 @Override 1583 public int getExpectedIResult() { 1584 return 2 + 2; 1585 } 1586 } 1587 1588 class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFrames extends EATestCaseBaseDebugger { 1589 1590 public void runTestCase() throws Exception { 1591 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1592 printStack(bpe.thread()); 1593 ObjectReference xy = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "xy"); 1594 ObjectReference alias = getLocalRef(bpe.thread().frame(1), "testMethod_inlined", "alias", XYVAL_NAME); 1595 Asserts.assertSame(xy, alias, "xy and alias are expected to reference the same object"); 1596 } 1597 1598 } 1599 1600 ///////////////////////////////////////////////////////////////////////////// 1601 1602 // Two local variables of the same compiled frame but in different virtual frames reference the same 1603 // object. 1604 // Check if it has the expected effect in the target if the debugger modifies the object. 1605 class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModifyTarget extends EATestCaseBaseTarget { 1606 1607 @Override 1608 public void setUp() { 1609 super.setUp(); 1610 testMethodDepth = 2; 1611 } 1612 1613 public void dontinline_testMethod() { 1614 XYVal xy = new XYVal(2, 3); 1615 testMethod_inlined(xy); // debugger: xy.x = 42 1616 iResult += xy.x; 1617 } 1618 1619 public void testMethod_inlined(XYVal xy) { 1620 XYVal alias = xy; 1621 dontinline_brkpt(); 1622 iResult = alias.x; 1623 } 1624 1625 @Override 1626 public int getExpectedIResult() { 1627 return 42 + 42; 1628 } 1629 } 1630 1631 class EAMaterializeObjReferencedBy2LocalsInDifferentVirtFramesAndModify extends EATestCaseBaseDebugger { 1632 1633 public void runTestCase() throws Exception { 1634 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1635 printStack(bpe.thread()); 1636 ObjectReference alias = getLocalRef(bpe.thread().frame(1), "testMethod_inlined", "alias", XYVAL_NAME); 1637 setField(alias, "x", env.vm().mirrorOf(42)); 1638 } 1639 1640 } 1641 1642 ///////////////////////////////////////////////////////////////////////////// 1643 1644 // Test materialization of an object referenced only from expression stack 1645 class EAMaterializeObjReferencedFromOperandStackTarget extends EATestCaseBaseTarget { 1646 1647 @Override 1648 public void setUp() { 1649 super.setUp(); 1650 testMethodDepth = 2; 1651 } 1652 1653 public void dontinline_testMethod() { 1654 @SuppressWarnings("unused") 1655 XYVal xy1 = new XYVal(2, 3); 1656 // Debugger breaks in call to dontinline_brkpt_ret_100() and reads 1657 // the value of the local 'xy1'. This triggers materialization 1658 // of the object on the operand stack 1659 iResult = testMethodInlined(new XYVal(4, 2), dontinline_brkpt_ret_100()); 1660 } 1661 1662 public int testMethodInlined(XYVal xy2, int dontinline_brkpt_ret_100) { 1663 return xy2.x + dontinline_brkpt_ret_100; 1664 } 1665 1666 public int dontinline_brkpt_ret_100() { 1667 dontinline_brkpt(); 1668 return 100; 1669 } 1670 1671 @Override 1672 public int getExpectedIResult() { 1673 return 4 + 100; 1674 } 1675 } 1676 1677 class EAMaterializeObjReferencedFromOperandStack extends EATestCaseBaseDebugger { 1678 1679 public void runTestCase() throws Exception { 1680 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1681 printStack(bpe.thread()); 1682 ObjectReference xy1 = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "xy1"); 1683 checkPrimitiveField(xy1, FD.I, "x", 2); 1684 checkPrimitiveField(xy1, FD.I, "y", 3); 1685 } 1686 1687 } 1688 1689 ///////////////////////////////////////////////////////////////////////////// 1690 1691 /** 1692 * Tests a regression in the implementation by setting the value of a local int which triggers the 1693 * creation of a deferred update and then getting the reference to a scalar replaced object. The 1694 * issue was that the scalar replaced object was not reallocated. Because of the deferred update it 1695 * was assumed that the reallocation already happened. 1696 */ 1697 class EAMaterializeLocalVariableUponGetAfterSetInteger extends EATestCaseBaseDebugger { 1698 1699 public void runTestCase() throws Exception { 1700 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1701 printStack(bpe.thread()); 1702 setLocal(bpe.thread().frame(1), "i", env.vm().mirrorOf(43)); 1703 ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy"); 1704 checkPrimitiveField(o, FD.I, "x", 4); 1705 checkPrimitiveField(o, FD.I, "y", 2); 1706 } 1707 } 1708 1709 class EAMaterializeLocalVariableUponGetAfterSetIntegerTarget extends EATestCaseBaseTarget { 1710 1711 public void dontinline_testMethod() { 1712 XYVal xy = new XYVal(4, 2); 1713 int i = 42; 1714 dontinline_brkpt(); 1715 iResult = xy.x + xy.y + i; 1716 } 1717 1718 @Override 1719 public int getExpectedIResult() { 1720 return 4 + 2 + 43; 1721 } 1722 1723 @Override 1724 public boolean testFrameShouldBeDeoptimized() { 1725 return true; // setting local variable i always triggers deoptimization 1726 } 1727 } 1728 1729 ///////////////////////////////////////////////////////////////////////////// 1730 // 1731 // Locking Tests 1732 // 1733 ///////////////////////////////////////////////////////////////////////////// 1734 1735 class EARelockingSimple extends EATestCaseBaseDebugger { 1736 1737 public void runTestCase() throws Exception { 1738 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1739 printStack(bpe.thread()); 1740 @SuppressWarnings("unused") 1741 ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "l1"); 1742 } 1743 } 1744 1745 class EARelockingSimpleTarget extends EATestCaseBaseTarget { 1746 1747 public void dontinline_testMethod() { 1748 XYVal l1 = new XYVal(4, 2); 1749 synchronized (l1) { 1750 dontinline_brkpt(); 1751 } 1752 } 1753 } 1754 1755 ///////////////////////////////////////////////////////////////////////////// 1756 1757 // The debugger reads and publishes an object with eliminated locking to an instance field. 1758 // A 2nd thread in the debuggee finds it there and changes its state using a synchronized method. 1759 // Without eager relocking the accesses are unsynchronized which can be observed. 1760 class EARelockingSimpleWithAccessInOtherThread extends EATestCaseBaseDebugger { 1761 1762 public void runTestCase() throws Exception { 1763 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1764 printStack(bpe.thread()); 1765 String l1ClassName = EARelockingSimpleWithAccessInOtherThreadTarget.SyncCounter.class.getName(); 1766 ObjectReference ctr = getLocalRef(bpe.thread().frame(1), l1ClassName, "l1"); 1767 setField(testCase, "sharedCounter", ctr); 1768 terminateEndlessLoop(); 1769 } 1770 } 1771 1772 class EARelockingSimpleWithAccessInOtherThreadTarget extends EATestCaseBaseTarget { 1773 1774 public static class SyncCounter { 1775 private int val; 1776 public synchronized int inc() { return val++; } 1777 } 1778 1779 public volatile SyncCounter sharedCounter; 1780 1781 @Override 1782 public void setUp() { 1783 super.setUp(); 1784 doLoop = true; 1785 Thread.ofPlatform().daemon().start(() -> { 1786 while (doLoop) { 1787 SyncCounter ctr = sharedCounter; 1788 if (ctr != null) { 1789 ctr.inc(); 1790 } 1791 } 1792 }); 1793 } 1794 1795 public void dontinline_testMethod() { 1796 SyncCounter l1 = new SyncCounter(); 1797 synchronized (l1) { // Eliminated locking 1798 l1.inc(); 1799 dontinline_brkpt(); // Debugger publishes l1 to sharedCounter. 1800 iResult = l1.inc(); // Changes by the 2nd thread will be observed if l1 1801 // was not relocked before passing it to the debugger. 1802 } 1803 } 1804 1805 @Override 1806 public int getExpectedIResult() { 1807 return 1; 1808 } 1809 } 1810 1811 ///////////////////////////////////////////////////////////////////////////// 1812 1813 // The debugger reads and publishes an object with eliminated locking to an instance field. 1814 // A 2nd thread in the debuggee finds it there and changes its state using a synchronized method. 1815 // Without eager relocking the accesses are unsynchronized which can be observed. 1816 // This is a variant of EARelockingSimpleWithAccessInOtherThread with a dynamic call (not devirtualized). 1817 class EARelockingSimpleWithAccessInOtherThread_02_DynamicCall extends EATestCaseBaseDebugger { 1818 1819 public void runTestCase() throws Exception { 1820 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1821 printStack(bpe.thread()); 1822 String l1ClassName = EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target.SyncCounter.class.getName(); 1823 ObjectReference ctr = getLocalRef(bpe.thread().frame(2), l1ClassName, "l1"); 1824 setField(testCase, "sharedCounter", ctr); 1825 terminateEndlessLoop(); 1826 } 1827 } 1828 1829 class EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target extends EATestCaseBaseTarget { 1830 1831 public static final BrkPtDispatchA[] disp = 1832 {new BrkPtDispatchA(), new BrkPtDispatchB(), new BrkPtDispatchC(), new BrkPtDispatchD()}; 1833 1834 public static class BrkPtDispatchA { 1835 public EATestCaseBaseTarget testCase; 1836 public void dontinline_brkpt() { testCase.dontinline_brkpt(); } 1837 } 1838 1839 public static class BrkPtDispatchB extends BrkPtDispatchA { 1840 @Override 1841 public void dontinline_brkpt() { testCase.dontinline_brkpt(); } 1842 } 1843 1844 public static class BrkPtDispatchC extends BrkPtDispatchA { 1845 @Override 1846 public void dontinline_brkpt() { testCase.dontinline_brkpt(); } 1847 } 1848 1849 public static class BrkPtDispatchD extends BrkPtDispatchA { 1850 @Override 1851 public void dontinline_brkpt() { 1852 testCase.dontinline_brkpt(); 1853 } 1854 } 1855 1856 public static class SyncCounter { 1857 private int val; 1858 public synchronized int inc() { return val++; } 1859 } 1860 1861 public volatile SyncCounter sharedCounter; 1862 1863 @Override 1864 public void setUp() { 1865 super.setUp(); 1866 testMethodDepth = 2; 1867 for (BrkPtDispatchA d : disp) { 1868 d.testCase = this; 1869 } 1870 doLoop = true; 1871 new Thread(() -> { 1872 while (doLoop) { 1873 SyncCounter ctr = sharedCounter; 1874 if (ctr != null) { 1875 ctr.inc(); 1876 } 1877 } 1878 }).start(); 1879 } 1880 1881 public int dispCount; 1882 public void dontinline_testMethod() { 1883 SyncCounter l1 = new SyncCounter(); 1884 synchronized (l1) { // Eliminated locking 1885 l1.inc(); 1886 // Use different types for the subsequent call to prevent devirtualization. 1887 BrkPtDispatchA d = disp[(dispCount++) & 3]; 1888 d.dontinline_brkpt(); // Dynamic call. Debugger publishes l1 to sharedCounter. 1889 iResult = l1.inc(); // Changes by the 2nd thread will be observed if l1 1890 // was not relocked before passing it to the debugger. 1891 } 1892 } 1893 1894 @Override 1895 public int getExpectedIResult() { 1896 return 1; 1897 } 1898 } 1899 1900 ///////////////////////////////////////////////////////////////////////////// 1901 1902 // Test recursive locking 1903 class EARelockingRecursiveTarget extends EATestCaseBaseTarget { 1904 1905 @Override 1906 public void setUp() { 1907 super.setUp(); 1908 testMethodDepth = 2; 1909 } 1910 1911 public void dontinline_testMethod() { 1912 XYVal l1 = new XYVal(4, 2); 1913 synchronized (l1) { 1914 testMethod_inlined(l1); 1915 } 1916 } 1917 1918 public void testMethod_inlined(XYVal l2) { 1919 synchronized (l2) { 1920 dontinline_brkpt(); 1921 } 1922 } 1923 } 1924 1925 class EARelockingRecursive extends EATestCaseBaseDebugger { 1926 1927 public void runTestCase() throws Exception { 1928 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1929 printStack(bpe.thread()); 1930 @SuppressWarnings("unused") 1931 ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1"); 1932 } 1933 } 1934 1935 ///////////////////////////////////////////////////////////////////////////// 1936 1937 // Object ref l1 is retrieved by the debugger at a location where nested locks are omitted. The 1938 // accessed object is globally reachable already before the access, therefore no relocking is done. 1939 class EARelockingNestedInflatedTarget extends EATestCaseBaseTarget { 1940 1941 @Override 1942 public void setUp() { 1943 super.setUp(); 1944 testMethodDepth = 2; 1945 } 1946 1947 @Override 1948 public boolean testFrameShouldBeDeoptimized() { 1949 // Access does not trigger deopt., as escape state is already global escape. 1950 return false; 1951 } 1952 1953 public void dontinline_testMethod() { 1954 XYVal l1 = inflatedLock; 1955 synchronized (l1) { 1956 testMethod_inlined(l1); 1957 } 1958 } 1959 1960 public void testMethod_inlined(XYVal l2) { 1961 synchronized (l2) { // eliminated nested locking 1962 dontinline_brkpt(); 1963 } 1964 } 1965 } 1966 1967 class EARelockingNestedInflated extends EATestCaseBaseDebugger { 1968 1969 public void runTestCase() throws Exception { 1970 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1971 printStack(bpe.thread()); 1972 @SuppressWarnings("unused") 1973 ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1"); 1974 } 1975 } 1976 1977 ///////////////////////////////////////////////////////////////////////////// 1978 1979 /** 1980 * Like {@link EARelockingNestedInflated} with the difference that there is 1981 * a scalar replaced object in the scope from which the object with eliminated nested locking 1982 * is read. This triggers materialization and relocking. 1983 */ 1984 class EARelockingNestedInflated_02 extends EATestCaseBaseDebugger { 1985 1986 public void runTestCase() throws Exception { 1987 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 1988 printStack(bpe.thread()); 1989 @SuppressWarnings("unused") 1990 ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1"); 1991 } 1992 } 1993 1994 class EARelockingNestedInflated_02Target extends EATestCaseBaseTarget { 1995 1996 @Override 1997 public void setUp() { 1998 super.setUp(); 1999 testMethodDepth = 2; 2000 } 2001 2002 public void dontinline_testMethod() { 2003 @SuppressWarnings("unused") 2004 XYVal xy = new XYVal(1, 1); // scalar replaced 2005 XYVal l1 = inflatedLock; // read by debugger 2006 synchronized (l1) { 2007 testMethod_inlined(l1); 2008 } 2009 } 2010 2011 public void testMethod_inlined(XYVal l2) { 2012 synchronized (l2) { // eliminated nested locking 2013 dontinline_brkpt(); 2014 } 2015 } 2016 } 2017 2018 ///////////////////////////////////////////////////////////////////////////// 2019 2020 /** 2021 * Checks if an eliminated lock of an ArgEscape object l1 can be relocked if 2022 * l1 is locked in a callee frame. 2023 */ 2024 class EARelockingArgEscapeLWLockedInCalleeFrame extends EATestCaseBaseDebugger { 2025 2026 public void runTestCase() throws Exception { 2027 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2028 printStack(bpe.thread()); 2029 @SuppressWarnings("unused") 2030 ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1"); 2031 } 2032 } 2033 2034 class EARelockingArgEscapeLWLockedInCalleeFrameTarget extends EATestCaseBaseTarget { 2035 2036 @Override 2037 public void setUp() { 2038 super.setUp(); 2039 testMethodDepth = 2; 2040 } 2041 2042 public void dontinline_testMethod() { 2043 XYVal l1 = new XYVal(1, 1); // ArgEscape 2044 synchronized (l1) { // eliminated 2045 l1.dontinline_sync_method(this); // l1 escapes 2046 } 2047 } 2048 2049 @Override 2050 public boolean testFrameShouldBeDeoptimized() { 2051 // Graal does not provide debug info about arg escape objects, therefore the frame is not deoptimized 2052 return !UseJVMCICompiler && super.testFrameShouldBeDeoptimized(); 2053 } 2054 } 2055 2056 ///////////////////////////////////////////////////////////////////////////// 2057 2058 /** 2059 * Similar to {@link EARelockingArgEscapeLWLockedInCalleeFrame}. In addition 2060 * the test method has got a scalar replaced object with eliminated locking. 2061 * This pattern matches a regression in the implementation. 2062 */ 2063 class EARelockingArgEscapeLWLockedInCalleeFrame_2 extends EATestCaseBaseDebugger { 2064 2065 public void runTestCase() throws Exception { 2066 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2067 printStack(bpe.thread()); 2068 @SuppressWarnings("unused") 2069 ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1"); 2070 } 2071 } 2072 2073 class EARelockingArgEscapeLWLockedInCalleeFrame_2Target extends EATestCaseBaseTarget { 2074 2075 @Override 2076 public void setUp() { 2077 super.setUp(); 2078 testMethodDepth = 2; 2079 } 2080 2081 public void dontinline_testMethod() { 2082 XYVal l1 = new XYVal(1, 1); // ArgEscape 2083 XYVal l2 = new XYVal(4, 2); // NoEscape, scalar replaced 2084 synchronized (l1) { // eliminated 2085 synchronized (l2) { // eliminated 2086 l1.dontinline_sync_method(this); // l1 escapes 2087 } 2088 } 2089 iResult = l2.x + l2.y; 2090 } 2091 2092 @Override 2093 public int getExpectedIResult() { 2094 return 6; 2095 } 2096 } 2097 2098 ///////////////////////////////////////////////////////////////////////////// 2099 2100 /** 2101 * Similar to {@link EARelockingArgEscapeLWLockedInCalleeFrame_2Target}. It does 2102 * not use recursive locking and exposed a bug in the lightweight-locking implementation. 2103 */ 2104 class EARelockingArgEscapeLWLockedInCalleeFrameNoRecursive extends EATestCaseBaseDebugger { 2105 2106 public void runTestCase() throws Exception { 2107 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2108 printStack(bpe.thread()); 2109 @SuppressWarnings("unused") 2110 ObjectReference o = getLocalRef(bpe.thread().frame(2), XYVAL_NAME, "l1"); 2111 } 2112 } 2113 2114 class EARelockingArgEscapeLWLockedInCalleeFrameNoRecursiveTarget extends EATestCaseBaseTarget { 2115 2116 @Override 2117 public void setUp() { 2118 super.setUp(); 2119 testMethodDepth = 2; 2120 } 2121 2122 public void dontinline_testMethod() { 2123 XYVal l1 = new XYVal(1, 1); // NoEscape, scalar replaced 2124 XYVal l2 = new XYVal(4, 2); // NoEscape, scalar replaced 2125 XYVal l3 = new XYVal(5, 3); // ArgEscape 2126 synchronized (l1) { // eliminated 2127 synchronized (l2) { // eliminated 2128 l3.dontinline_sync_method(this); // l3 escapes 2129 } 2130 } 2131 iResult = l2.x + l2.y; 2132 } 2133 2134 @Override 2135 public int getExpectedIResult() { 2136 return 6; 2137 } 2138 } 2139 2140 ///////////////////////////////////////////////////////////////////////////// 2141 2142 /** 2143 * Test relocking eliminated (nested) locks of an object on which the 2144 * target thread currently waits. 2145 */ 2146 class EARelockingObjectCurrentlyWaitingOn extends EATestCaseBaseDebugger { 2147 2148 public void runTestCase() throws Exception { 2149 env.vm().resume(); 2150 boolean inWait = false; 2151 do { 2152 Thread.sleep(100); 2153 env.targetMainThread.suspend(); 2154 printStack(env.targetMainThread); 2155 inWait = env.targetMainThread.frame(0).location().method().name().equals("wait0"); 2156 if (!inWait) { 2157 msg("Target not yet in java.lang.Object.wait(long)."); 2158 env.targetMainThread.resume(); 2159 } 2160 } while(!inWait); 2161 StackFrame testMethodFrame = env.targetMainThread.frame(5); 2162 // Access triggers relocking of all eliminated locks, including nested locks of l1 which references 2163 // the object on which the target main thread is currently waiting. 2164 ObjectReference l0 = getLocalRef(testMethodFrame, EARelockingObjectCurrentlyWaitingOnTarget.ForLocking.class.getName(), "l0"); 2165 Asserts.assertEQ(l0.entryCount(), 1, "wrong entry count"); 2166 ObjectReference l1 = getLocalRef(testMethodFrame, EARelockingObjectCurrentlyWaitingOnTarget.ForLocking.class.getName(), "l1"); 2167 Asserts.assertEQ(l1.entryCount(), 0, "wrong entry count"); 2168 setField(testCase, "objToNotifyOn", l1); 2169 } 2170 } 2171 2172 class EARelockingObjectCurrentlyWaitingOnTarget extends EATestCaseBaseTarget { 2173 2174 public static class ForLocking { 2175 } 2176 2177 public volatile Object objToNotifyOn; // debugger assigns value when notify thread should call objToNotifyOn.notifyAll() 2178 2179 @Override 2180 public void setUp() { 2181 super.setUp(); 2182 testMethodDepth = 2; 2183 } 2184 2185 @Override 2186 public void warmupDone() { 2187 super.warmupDone(); 2188 Thread t = new Thread(() -> doNotify()); 2189 t.start(); 2190 } 2191 2192 public void doNotify() { 2193 while (objToNotifyOn == null) { 2194 try { 2195 msg("objToNotifyOn is still null"); 2196 Thread.sleep(100); 2197 } catch (InterruptedException e) { /* ignored */ } 2198 } 2199 synchronized (objToNotifyOn) { 2200 // will be received by the target main thread waiting in dontinline_waitWhenWarmupDone 2201 msg("calling objToNotifyOn.notifyAll()"); 2202 objToNotifyOn.notifyAll(); 2203 } 2204 } 2205 2206 @Override 2207 public boolean testFrameShouldBeDeoptimized() { 2208 return false; 2209 } 2210 2211 @Override 2212 public void dontinline_testMethod() throws Exception { 2213 ForLocking l0 = new ForLocking(); // will be scalar replaced; access triggers realloc/relock 2214 ForLocking l1 = new ForLocking(); 2215 synchronized (l0) { 2216 synchronized (l1) { 2217 testMethod_inlined(l1); 2218 } 2219 } 2220 } 2221 2222 public void testMethod_inlined(ForLocking l2) throws Exception { 2223 synchronized (l2) { // eliminated nested locking 2224 dontinline_waitWhenWarmupDone(l2); 2225 } 2226 } 2227 2228 public void dontinline_waitWhenWarmupDone(ForLocking l2) throws Exception { 2229 if (warmupDone) { 2230 l2.wait(); 2231 } 2232 } 2233 } 2234 2235 ///////////////////////////////////////////////////////////////////////////// 2236 // 2237 // Test cases that require deoptimization even though neither locks 2238 // nor allocations are eliminated at the point where escape state is changed. 2239 // 2240 ///////////////////////////////////////////////////////////////////////////// 2241 2242 /** 2243 * Let xy be NoEscape whose allocation cannot be eliminated (simulated by 2244 * -XX:-EliminateAllocations). The holding compiled frame has to be deoptimized when debugger 2245 * accesses xy because afterwards locking on xy is omitted. 2246 * Note: there are no EA based optimizations at the escape point. 2247 */ 2248 class EADeoptFrameAfterReadLocalObject_01 extends EATestCaseBaseDebugger { 2249 2250 public void runTestCase() throws Exception { 2251 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2252 printStack(bpe.thread()); 2253 @SuppressWarnings("unused") 2254 ObjectReference xy = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy"); 2255 } 2256 } 2257 2258 class EADeoptFrameAfterReadLocalObject_01Target extends EATestCaseBaseTarget { 2259 2260 public void dontinline_testMethod() { 2261 XYVal xy = new XYVal(1, 1); 2262 dontinline_brkpt(); // Debugger reads xy, when there are no virtual objects or eliminated locks in scope 2263 synchronized (xy) { // Locking is eliminated. 2264 xy.x++; 2265 xy.y++; 2266 } 2267 } 2268 } 2269 2270 ///////////////////////////////////////////////////////////////////////////// 2271 2272 /** 2273 * Similar to {@link EADeoptFrameAfterReadLocalObject_01} with the difference that the debugger 2274 * reads xy from an inlined callee. So xy is NoEscape instead of ArgEscape. 2275 */ 2276 class EADeoptFrameAfterReadLocalObject_01BTarget extends EATestCaseBaseTarget { 2277 2278 @Override 2279 public void setUp() { 2280 super.setUp(); 2281 testMethodDepth = 2; 2282 } 2283 2284 public void dontinline_testMethod() { 2285 XYVal xy = new XYVal(1, 1); 2286 callee(xy); // Debugger acquires ref to xy from inlined callee 2287 // xy is NoEscape, nevertheless the object is not replaced 2288 // by scalars if running with -XX:-EliminateAllocations. 2289 // In that case there are no EA based optimizations were 2290 // the debugger reads the NoEscape object. 2291 synchronized (xy) { // Locking is eliminated. 2292 xy.x++; 2293 xy.y++; 2294 } 2295 } 2296 2297 public void callee(XYVal xy) { 2298 dontinline_brkpt(); // Debugger reads xy. 2299 // There are no virtual objects or eliminated locks. 2300 } 2301 } 2302 2303 class EADeoptFrameAfterReadLocalObject_01B extends EATestCaseBaseDebugger { 2304 2305 public void runTestCase() throws Exception { 2306 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2307 printStack(bpe.thread()); 2308 @SuppressWarnings("unused") 2309 ObjectReference xy = getLocalRef(bpe.thread().frame(1), "callee", "xy", XYVAL_NAME); 2310 } 2311 } 2312 2313 ///////////////////////////////////////////////////////////////////////////// 2314 2315 /** 2316 * Let xy be ArgEscape. The frame dontinline_testMethod() has to be deoptimized when debugger 2317 * acquires xy from dontinline_callee() because afterwards locking on xy is omitted. 2318 * Note: there are no EA based optimizations at the escape point. 2319 */ 2320 class EADeoptFrameAfterReadLocalObject_02 extends EATestCaseBaseDebugger { 2321 2322 public void runTestCase() throws Exception { 2323 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2324 printStack(bpe.thread()); 2325 @SuppressWarnings("unused") 2326 ObjectReference xy = getLocalRef(bpe.thread().frame(1), "dontinline_callee", "xy", XYVAL_NAME); 2327 } 2328 } 2329 2330 class EADeoptFrameAfterReadLocalObject_02Target extends EATestCaseBaseTarget { 2331 2332 public void dontinline_testMethod() { 2333 XYVal xy = new XYVal(1, 1); 2334 dontinline_callee(xy); // xy is ArgEscape, debugger acquires ref to xy from callee 2335 synchronized (xy) { // Locking is eliminated. 2336 xy.x++; 2337 xy.y++; 2338 } 2339 } 2340 2341 public void dontinline_callee(XYVal xy) { 2342 dontinline_brkpt(); // Debugger reads xy. 2343 // There are no virtual objects or eliminated locks. 2344 } 2345 2346 @Override 2347 public void setUp() { 2348 super.setUp(); 2349 testMethodDepth = 2; 2350 } 2351 2352 @Override 2353 public boolean testFrameShouldBeDeoptimized() { 2354 // Graal does not provide debug info about arg escape objects, therefore the frame is not deoptimized 2355 return !UseJVMCICompiler && super.testFrameShouldBeDeoptimized(); 2356 } 2357 } 2358 2359 ///////////////////////////////////////////////////////////////////////////// 2360 2361 /** 2362 * Similar to {@link EADeoptFrameAfterReadLocalObject_02} there is an ArgEscape object xy, but in 2363 * contrast it is not in the parameter list of a call when the debugger reads an object. 2364 * Therefore the frame of the test method should not be deoptimized 2365 */ 2366 class EADeoptFrameAfterReadLocalObject_02B extends EATestCaseBaseDebugger { 2367 2368 public void runTestCase() throws Exception { 2369 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2370 printStack(bpe.thread()); 2371 @SuppressWarnings("unused") 2372 ObjectReference xy = getLocalRef(bpe.thread().frame(1), "dontinline_callee", "xy", XYVAL_NAME); 2373 } 2374 } 2375 2376 class EADeoptFrameAfterReadLocalObject_02BTarget extends EATestCaseBaseTarget { 2377 2378 public void dontinline_testMethod() { 2379 XYVal xy = new XYVal(1, 1); 2380 dontinline_make_arg_escape(xy); // because of this call xy is ArgEscape 2381 dontinline_callee(); // xy is ArgEscape, but not a parameter of this call 2382 synchronized (xy) { // Locking is eliminated. 2383 xy.x++; 2384 xy.y++; 2385 } 2386 } 2387 2388 public void dontinline_callee() { 2389 @SuppressWarnings("unused") 2390 XYVal xy = new XYVal(2, 2); 2391 dontinline_brkpt(); // Debugger reads xy. 2392 // No need to deoptimize the caller frame 2393 } 2394 2395 @Override 2396 public void setUp() { 2397 super.setUp(); 2398 testMethodDepth = 2; 2399 } 2400 2401 @Override 2402 public boolean testFrameShouldBeDeoptimized() { 2403 return false; 2404 } 2405 } 2406 2407 ///////////////////////////////////////////////////////////////////////////// 2408 2409 /** 2410 * Similar to {@link EADeoptFrameAfterReadLocalObject_02} there is an ArgEscape object xy in 2411 * dontinline_testMethod() which is being passed as parameter when the debugger accesses a local object. 2412 * Nevertheless dontinline_testMethod must not be deoptimized because there is an entry frame 2413 * between it and the frame accessed by the debugger. 2414 */ 2415 class EADeoptFrameAfterReadLocalObject_02C extends EATestCaseBaseDebugger { 2416 2417 public void runTestCase() throws Exception { 2418 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2419 printStack(bpe.thread()); 2420 @SuppressWarnings("unused") 2421 ObjectReference xy = getLocalRef(bpe.thread().frame(1), "dontinline_callee_accessed_by_debugger", "xy", XYVAL_NAME); 2422 } 2423 } 2424 2425 class EADeoptFrameAfterReadLocalObject_02CTarget extends EATestCaseBaseTarget { 2426 2427 public void dontinline_testMethod() { 2428 XYVal xy = new XYVal(1, 1); 2429 dontinline_callee(xy); // xy is ArgEscape and being passed as parameter 2430 synchronized (xy) { // Locking is eliminated. 2431 xy.x++; 2432 xy.y++; 2433 } 2434 } 2435 2436 public void dontinline_callee(XYVal xy) { 2437 if (warmupDone) { 2438 dontinline_call_with_entry_frame(this, "dontinline_callee_accessed_by_debugger"); 2439 } 2440 } 2441 2442 public void dontinline_callee_accessed_by_debugger() { 2443 @SuppressWarnings("unused") 2444 XYVal xy = new XYVal(2, 2); 2445 dontinline_brkpt(); // Debugger reads xy. 2446 // No need to deoptimize the caller frame 2447 } 2448 2449 @Override 2450 public void setUp() { 2451 super.setUp(); 2452 // the method depth in debuggee is 11 as it includes all hidden frames 2453 // the expected method depth is 6 excluding 5 hidden frames 2454 testMethodDepth = 11-5; 2455 } 2456 2457 @Override 2458 public boolean testFrameShouldBeDeoptimized() { 2459 return false; 2460 } 2461 } 2462 2463 ///////////////////////////////////////////////////////////////////////////// 2464 2465 /** 2466 * Let xy be NoEscape whose allocation cannot be eliminated (e.g. because of 2467 * -XX:-EliminateAllocations). The holding compiled frame has to be deoptimized when debugger 2468 * accesses xy because the following field accesses get eliminated. Note: there are no EA based 2469 * optimizations at the escape point. 2470 */ 2471 class EADeoptFrameAfterReadLocalObject_03 extends EATestCaseBaseDebugger { 2472 2473 public void runTestCase() throws Exception { 2474 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2475 printStack(bpe.thread()); 2476 ObjectReference xy = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "xy"); 2477 setField(xy, "x", env.vm().mirrorOf(1)); 2478 } 2479 } 2480 2481 class EADeoptFrameAfterReadLocalObject_03Target extends EATestCaseBaseTarget { 2482 2483 public void dontinline_testMethod() { 2484 XYVal xy = new XYVal(0, 1); 2485 dontinline_brkpt(); // Debugger reads xy, when there are no virtual objects or 2486 // eliminated locks in scope and modifies xy.x 2487 iResult = xy.x + xy.y; // Loads are replaced by constants 0 and 1. 2488 } 2489 2490 @Override 2491 public int getExpectedIResult() { 2492 return 1 + 1; 2493 } 2494 } 2495 2496 ///////////////////////////////////////////////////////////////////////////// 2497 // 2498 // Monitor info tests 2499 // 2500 ///////////////////////////////////////////////////////////////////////////// 2501 2502 class EAGetOwnedMonitorsTarget extends EATestCaseBaseTarget { 2503 2504 public long checkSum; 2505 2506 public void dontinline_testMethod() { 2507 XYVal l1 = new XYVal(4, 2); 2508 synchronized (l1) { 2509 dontinline_endlessLoop(); 2510 } 2511 } 2512 2513 @Override 2514 public void setUp() { 2515 super.setUp(); 2516 testMethodDepth = 2; 2517 loopCount = 3; 2518 } 2519 2520 public void warmupDone() { 2521 super.warmupDone(); 2522 msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE"); 2523 loopCount = Long.MAX_VALUE; // endless loop 2524 } 2525 } 2526 2527 class EAGetOwnedMonitors extends EATestCaseBaseDebugger { 2528 2529 public void runTestCase() throws Exception { 2530 msg("resume"); 2531 env.vm().resume(); 2532 waitUntilTargetHasEnteredEndlessLoop(); 2533 // In contrast to JVMTI, JDWP requires a target thread to be suspended, before the owned monitors can be queried 2534 msg("suspend target"); 2535 env.targetMainThread.suspend(); 2536 msg("Get owned monitors"); 2537 List<ObjectReference> monitors = env.targetMainThread.ownedMonitors(); 2538 Asserts.assertEQ(monitors.size(), 1, "unexpected number of owned monitors"); 2539 terminateEndlessLoop(); 2540 } 2541 } 2542 2543 ///////////////////////////////////////////////////////////////////////////// 2544 2545 class EAEntryCountTarget extends EATestCaseBaseTarget { 2546 2547 public long checkSum; 2548 2549 public void dontinline_testMethod() { 2550 XYVal l1 = new XYVal(4, 2); 2551 synchronized (l1) { 2552 inline_testMethod2(l1); 2553 } 2554 } 2555 2556 public void inline_testMethod2(XYVal l1) { 2557 synchronized (l1) { 2558 dontinline_endlessLoop(); 2559 } 2560 } 2561 2562 @Override 2563 public void setUp() { 2564 super.setUp(); 2565 testMethodDepth = 2; 2566 loopCount = 3; 2567 } 2568 2569 public void warmupDone() { 2570 super.warmupDone(); 2571 msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE"); 2572 loopCount = Long.MAX_VALUE; // endless loop 2573 } 2574 } 2575 2576 class EAEntryCount extends EATestCaseBaseDebugger { 2577 2578 public void runTestCase() throws Exception { 2579 msg("resume"); 2580 env.vm().resume(); 2581 waitUntilTargetHasEnteredEndlessLoop(); 2582 // In contrast to JVMTI, JDWP requires a target thread to be suspended, before the owned monitors can be queried 2583 msg("suspend target"); 2584 env.targetMainThread.suspend(); 2585 msg("Get owned monitors"); 2586 List<ObjectReference> monitors = env.targetMainThread.ownedMonitors(); 2587 Asserts.assertEQ(monitors.size(), 1, "unexpected number of owned monitors"); 2588 msg("Get entry count"); 2589 int entryCount = monitors.get(0).entryCount(); 2590 Asserts.assertEQ(entryCount, 2, "wrong entry count"); 2591 terminateEndlessLoop(); 2592 } 2593 } 2594 2595 ///////////////////////////////////////////////////////////////////////////// 2596 // 2597 // PopFrame tests 2598 // 2599 ///////////////////////////////////////////////////////////////////////////// 2600 2601 /** 2602 * PopFrame into caller frame with scalar replaced objects. 2603 */ 2604 class EAPopFrameNotInlined extends EATestCaseBaseDebugger { 2605 2606 public void runTestCase() throws Exception { 2607 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2608 printStack(bpe.thread()); 2609 msg("PopFrame"); 2610 bpe.thread().popFrames(bpe.thread().frame(0)); 2611 msg("PopFrame DONE"); 2612 } 2613 2614 @Override 2615 public boolean shouldSkip() { 2616 // And Graal currently doesn't support PopFrame 2617 return super.shouldSkip() || env.targetVMOptions.UseJVMCICompiler; 2618 } 2619 } 2620 2621 class EAPopFrameNotInlinedTarget extends EATestCaseBaseTarget { 2622 2623 public void dontinline_testMethod() { 2624 XYVal xy = new XYVal(4, 2); 2625 dontinline_brkpt(); 2626 iResult = xy.x + xy.y; 2627 } 2628 2629 @Override 2630 public boolean testFrameShouldBeDeoptimized() { 2631 // Test is only performed after the frame pop. 2632 // Then dontinline_testMethod is interpreted. 2633 return false; 2634 } 2635 2636 @Override 2637 public int getExpectedIResult() { 2638 return 4 + 2; 2639 } 2640 2641 @Override 2642 public boolean shouldSkip() { 2643 // And Graal currently doesn't support PopFrame 2644 return super.shouldSkip() || UseJVMCICompiler; 2645 } 2646 } 2647 2648 ///////////////////////////////////////////////////////////////////////////// 2649 2650 /** 2651 * Pop frames into {@link EAPopFrameNotInlinedReallocFailureTarget#dontinline_testMethod()} which 2652 * holds scalar replaced objects. In preparation of the pop frame operations the vm eagerly 2653 * reallocates scalar replaced objects to avoid failures when actually popping the frames. We provoke 2654 * a reallocation failures and expect {@link VMOutOfMemoryException}. 2655 */ 2656 class EAPopFrameNotInlinedReallocFailure extends EATestCaseBaseDebugger { 2657 2658 public void runTestCase() throws Exception { 2659 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2660 ThreadReference thread = bpe.thread(); 2661 printStack(thread); 2662 // frame[0]: EATestCaseBaseTarget.dontinline_brkpt() 2663 // frame[1]: EAPopFrameNotInlinedReallocFailureTarget.dontinline_consume_all_memory_brkpt() 2664 // frame[2]: EAPopFrameNotInlinedReallocFailureTarget.dontinline_testMethod() 2665 // frame[3]: EATestCaseBaseTarget.run() 2666 // frame[4]: EATestsTarget.main(java.lang.String[]) 2667 msg("PopFrame"); 2668 boolean coughtOom = false; 2669 try { 2670 // try to pop dontinline_consume_all_memory_brkpt 2671 thread.popFrames(thread.frame(1)); 2672 } catch (VMOutOfMemoryException oom) { 2673 // as expected 2674 msg("cought OOM"); 2675 coughtOom = true; 2676 } 2677 freeAllMemory(); 2678 // We succeeded to pop just one frame. When we continue, we will call dontinline_brkpt() again. 2679 Asserts.assertTrue(coughtOom, "PopFrame should have triggered an OOM exception in target"); 2680 String expectedTopFrame = "dontinline_consume_all_memory_brkpt"; 2681 Asserts.assertEQ(expectedTopFrame, thread.frame(0).location().method().name()); 2682 printStack(thread); 2683 } 2684 2685 @Override 2686 public boolean shouldSkip() { 2687 // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. 2688 // And Graal currently doesn't provide all information about non-escaping objects in debug info 2689 return super.shouldSkip() || 2690 !env.targetVMOptions.EliminateAllocations || 2691 // With ZGC or Shenandoah the OOME is not always thrown as expected 2692 env.targetVMOptions.ZGCIsSelected || 2693 env.targetVMOptions.ShenandoahGCIsSelected || 2694 env.targetVMOptions.DeoptimizeObjectsALot || 2695 env.targetVMOptions.UseJVMCICompiler; 2696 } 2697 } 2698 2699 class EAPopFrameNotInlinedReallocFailureTarget extends EATestCaseBaseTarget { 2700 2701 public boolean doneAlready; 2702 2703 public void dontinline_testMethod() { 2704 long a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // scalar replaced 2705 Vector10 v = new Vector10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // scalar replaced 2706 dontinline_consume_all_memory_brkpt(); 2707 lResult = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] 2708 + v.i0 + v.i1 + v.i2 + v.i3 + v.i4 + v.i5 + v.i6 + v.i7 + v.i8 + v.i9; 2709 } 2710 2711 public void dontinline_consume_all_memory_brkpt() { 2712 if (warmupDone && !doneAlready) { 2713 doneAlready = true; 2714 consumeAllMemory(); // provoke reallocation failure 2715 dontinline_brkpt(); 2716 } 2717 } 2718 2719 @Override 2720 public void setUp() { 2721 super.setUp(); 2722 testMethodDepth = 2; 2723 } 2724 2725 @Override 2726 public long getExpectedLResult() { 2727 long n = 10; 2728 return 2*n*(n+1)/2; 2729 } 2730 2731 @Override 2732 public boolean shouldSkip() { 2733 // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. 2734 // And Graal currently doesn't provide all information about non-escaping objects in debug info 2735 return super.shouldSkip() || 2736 !EliminateAllocations || 2737 // With ZGC or Shenandoah the OOME is not always thrown as expected 2738 ZGCIsSelected || 2739 ShenandoahGCIsSelected || 2740 DeoptimizeObjectsALot || 2741 UseJVMCICompiler; 2742 } 2743 } 2744 2745 ///////////////////////////////////////////////////////////////////////////// 2746 2747 /** 2748 * Pop inlined top frame dropping into method with scalar replaced opjects. 2749 */ 2750 class EAPopInlinedMethodWithScalarReplacedObjectsReallocFailure extends EATestCaseBaseDebugger { 2751 2752 public void runTestCase() throws Exception { 2753 ThreadReference thread = env.targetMainThread; 2754 env.vm().resume(); 2755 waitUntilTargetHasEnteredEndlessLoop(); 2756 2757 thread.suspend(); 2758 printStack(thread); 2759 // frame[0]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.inlinedCallForcedToReturn() 2760 // frame[1]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.dontinline_testMethod() 2761 // frame[2]: EATestCaseBaseTarget.run() 2762 2763 msg("Pop Frames"); 2764 boolean coughtOom = false; 2765 try { 2766 thread.popFrames(thread.frame(0)); // Request pop frame of inlinedCallForcedToReturn() 2767 // reallocation is triggered here 2768 } catch (VMOutOfMemoryException oom) { 2769 // as expected 2770 msg("cought OOM"); 2771 coughtOom = true; 2772 } 2773 printStack(thread); 2774 // frame[0]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.inlinedCallForcedToReturn() 2775 // frame[1]: EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.dontinline_testMethod() 2776 // frame[2]: EATestCaseBaseTarget.run() 2777 2778 freeAllMemory(); 2779 setField(testCase, "loopCount", env.vm().mirrorOf(0)); // terminate loop 2780 Asserts.assertTrue(coughtOom, "PopFrame should have triggered an OOM exception in target"); 2781 String expectedTopFrame = "inlinedCallForcedToReturn"; 2782 Asserts.assertEQ(expectedTopFrame, thread.frame(0).location().method().name()); 2783 } 2784 2785 @Override 2786 public boolean shouldSkip() { 2787 // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. 2788 // And Graal currently doesn't provide all information about non-escaping objects in debug info 2789 return super.shouldSkip() || 2790 !env.targetVMOptions.EliminateAllocations || 2791 // With ZGC or Shenandoah the OOME is not always thrown as expected 2792 env.targetVMOptions.ZGCIsSelected || 2793 env.targetVMOptions.ShenandoahGCIsSelected || 2794 env.targetVMOptions.DeoptimizeObjectsALot || 2795 env.targetVMOptions.UseJVMCICompiler; 2796 } 2797 } 2798 2799 class EAPopInlinedMethodWithScalarReplacedObjectsReallocFailureTarget extends EATestCaseBaseTarget { 2800 2801 public long checkSum; 2802 2803 public void dontinline_testMethod() { 2804 long a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // scalar replaced 2805 Vector10 v = new Vector10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // scalar replaced 2806 long l = inlinedCallForcedToReturn(); 2807 lResult = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] 2808 + v.i0 + v.i1 + v.i2 + v.i3 + v.i4 + v.i5 + v.i6 + v.i7 + v.i8 + v.i9; 2809 } 2810 2811 public long inlinedCallForcedToReturn() { 2812 long cs = checkSum; 2813 dontinline_consumeAllMemory(); 2814 while (loopCount-- > 0) { 2815 targetIsInLoop = true; 2816 checkSum += checkSum % ++cs; 2817 } 2818 loopCount = 3; 2819 targetIsInLoop = false; 2820 return checkSum; 2821 } 2822 2823 public void dontinline_consumeAllMemory() { 2824 if (warmupDone && (loopCount > 3)) { 2825 consumeAllMemory(); 2826 } 2827 } 2828 2829 @Override 2830 public long getExpectedLResult() { 2831 long n = 10; 2832 return 2*n*(n+1)/2; 2833 } 2834 2835 @Override 2836 public void setUp() { 2837 super.setUp(); 2838 loopCount = 3; 2839 } 2840 2841 public void warmupDone() { 2842 super.warmupDone(); 2843 msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE"); 2844 loopCount = Long.MAX_VALUE; // endless loop 2845 } 2846 2847 @Override 2848 public boolean shouldSkip() { 2849 // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. 2850 // And Graal currently doesn't provide all information about non-escaping objects in debug info 2851 return super.shouldSkip() || 2852 !EliminateAllocations || 2853 // With ZGC or Shenandoah the OOME is not always thrown as expected 2854 ZGCIsSelected || 2855 ShenandoahGCIsSelected || 2856 DeoptimizeObjectsALot || 2857 UseJVMCICompiler; 2858 } 2859 } 2860 2861 ///////////////////////////////////////////////////////////////////////////// 2862 // 2863 // ForceEarlyReturn tests 2864 // 2865 ///////////////////////////////////////////////////////////////////////////// 2866 2867 /** 2868 * ForceEarlyReturn into caller frame with scalar replaced objects. 2869 */ 2870 class EAForceEarlyReturnNotInlined extends EATestCaseBaseDebugger { 2871 2872 public void runTestCase() throws Exception { 2873 BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); 2874 ThreadReference thread = bpe.thread(); 2875 printStack(thread); 2876 // frame[0]: EATestCaseBaseTarget.dontinline_brkpt() 2877 // frame[1]: EATestCaseBaseTarget.dontinline_brkpt_iret() 2878 // frame[2]: EAForceEarlyReturnNotInlinedTarget.dontinline_testMethod() 2879 // frame[3]: EATestCaseBaseTarget.run() 2880 // frame[4]: EATestsTarget.main(java.lang.String[]) 2881 2882 msg("Step out"); 2883 env.stepOut(thread); // return from dontinline_brkpt 2884 printStack(thread); 2885 msg("ForceEarlyReturn"); 2886 thread.forceEarlyReturn(env.vm().mirrorOf(43)); // return from dontinline_brkpt_iret, 2887 // does not trigger reallocation in contrast to PopFrame 2888 msg("Step over line"); 2889 env.stepOverLine(thread); // reallocation is triggered here 2890 printStack(thread); 2891 msg("ForceEarlyReturn DONE"); 2892 } 2893 2894 @Override 2895 public boolean shouldSkip() { 2896 // Graal currently doesn't support Force Early Return 2897 return super.shouldSkip() || env.targetVMOptions.UseJVMCICompiler; 2898 } 2899 } 2900 2901 class EAForceEarlyReturnNotInlinedTarget extends EATestCaseBaseTarget { 2902 2903 public void dontinline_testMethod() { 2904 XYVal xy = new XYVal(4, 2); 2905 int i = dontinline_brkpt_iret(); 2906 iResult = xy.x + xy.y + i; 2907 } 2908 2909 @Override 2910 public int getExpectedIResult() { 2911 return 4 + 2 + 43; 2912 } 2913 2914 @Override 2915 public void setUp() { 2916 super.setUp(); 2917 testMethodDepth = 2; 2918 } 2919 2920 public boolean testFrameShouldBeDeoptimized() { 2921 return true; // because of stepping 2922 } 2923 2924 @Override 2925 public boolean shouldSkip() { 2926 // Graal currently doesn't support Force Early Return 2927 return super.shouldSkip() || UseJVMCICompiler; 2928 } 2929 } 2930 2931 ///////////////////////////////////////////////////////////////////////////// 2932 2933 /** 2934 * ForceEarlyReturn at safepoint in frame with scalar replaced objects. 2935 */ 2936 class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjects extends EATestCaseBaseDebugger { 2937 2938 public void runTestCase() throws Exception { 2939 ThreadReference thread = env.targetMainThread; 2940 env.vm().resume(); 2941 waitUntilTargetHasEnteredEndlessLoop(); 2942 2943 thread.suspend(); 2944 printStack(thread); 2945 // frame[0]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget.inlinedCallForcedToReturn() 2946 // frame[1]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget.dontinline_testMethod() 2947 // frame[2]: EATestCaseBaseTarget.run() 2948 2949 msg("ForceEarlyReturn"); 2950 thread.forceEarlyReturn(env.vm().mirrorOf(43)); // Request force return 43 from inlinedCallForcedToReturn() 2951 // reallocation is triggered here 2952 msg("Step over instruction to do the forced return"); 2953 env.stepOverInstruction(thread); 2954 printStack(thread); 2955 msg("ForceEarlyReturn DONE"); 2956 } 2957 2958 @Override 2959 public boolean shouldSkip() { 2960 // Graal currently doesn't support Force Early Return 2961 return super.shouldSkip() || env.targetVMOptions.UseJVMCICompiler; 2962 } 2963 } 2964 2965 class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsTarget extends EATestCaseBaseTarget { 2966 2967 public int checkSum; 2968 2969 public void dontinline_testMethod() { 2970 XYVal xy = new XYVal(4, 2); 2971 int i = inlinedCallForcedToReturn(); 2972 iResult = xy.x + xy.y + i; 2973 } 2974 2975 public int inlinedCallForcedToReturn() { // forced to return 43 2976 int i = checkSum; 2977 while (loopCount-- > 0) { 2978 targetIsInLoop = true; 2979 checkSum += checkSum % ++i; 2980 } 2981 loopCount = 3; 2982 targetIsInLoop = false; 2983 return checkSum; 2984 } 2985 2986 @Override 2987 public int getExpectedIResult() { 2988 return 4 + 2 + 43; 2989 } 2990 2991 @Override 2992 public void setUp() { 2993 super.setUp(); 2994 testMethodDepth = 2; 2995 loopCount = 3; 2996 } 2997 2998 public void warmupDone() { 2999 super.warmupDone(); 3000 msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE"); 3001 loopCount = Long.MAX_VALUE; // endless loop 3002 } 3003 3004 public boolean testFrameShouldBeDeoptimized() { 3005 return true; // because of stepping 3006 } 3007 3008 @Override 3009 public boolean shouldSkip() { 3010 // Graal currently doesn't support Force Early Return 3011 return super.shouldSkip() || UseJVMCICompiler; 3012 } 3013 } 3014 3015 ///////////////////////////////////////////////////////////////////////////// 3016 3017 /** 3018 * ForceEarlyReturn with reallocation failure. 3019 */ 3020 class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailure extends EATestCaseBaseDebugger { 3021 3022 public void runTestCase() throws Exception { 3023 ThreadReference thread = env.targetMainThread; 3024 env.vm().resume(); 3025 waitUntilTargetHasEnteredEndlessLoop(); 3026 3027 thread.suspend(); 3028 printStack(thread); 3029 // frame[0]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.inlinedCallForcedToReturn() 3030 // frame[1]: EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget.dontinline_testMethod() 3031 // frame[2]: EATestCaseBaseTarget.run() 3032 3033 msg("ForceEarlyReturn"); 3034 boolean coughtOom = false; 3035 try { 3036 thread.forceEarlyReturn(env.vm().mirrorOf(43)); // Request force return 43 from inlinedCallForcedToReturn() 3037 // reallocation is triggered here 3038 } catch (VMOutOfMemoryException oom) { 3039 // as expected 3040 msg("cought OOM"); 3041 coughtOom = true; 3042 } 3043 freeAllMemory(); 3044 Asserts.assertTrue(coughtOom, "ForceEarlyReturn should have triggered an OOM exception in target"); 3045 printStack(thread); 3046 msg("ForceEarlyReturn(2)"); 3047 thread.forceEarlyReturn(env.vm().mirrorOf(43)); 3048 msg("Step over instruction to do the forced return"); 3049 env.stepOverInstruction(thread); 3050 printStack(thread); 3051 msg("ForceEarlyReturn DONE"); 3052 } 3053 3054 @Override 3055 public boolean shouldSkip() { 3056 // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. 3057 // And Graal currently doesn't support Force Early Return 3058 return super.shouldSkip() || 3059 !env.targetVMOptions.EliminateAllocations || 3060 // With ZGC or Shenandoah the OOME is not always thrown as expected 3061 env.targetVMOptions.ZGCIsSelected || 3062 env.targetVMOptions.ShenandoahGCIsSelected || 3063 env.targetVMOptions.DeoptimizeObjectsALot || 3064 env.targetVMOptions.UseJVMCICompiler; 3065 } 3066 } 3067 3068 class EAForceEarlyReturnOfInlinedMethodWithScalarReplacedObjectsReallocFailureTarget extends EATestCaseBaseTarget { 3069 3070 public int checkSum; 3071 3072 public void dontinline_testMethod() { 3073 long a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // scalar replaced 3074 Vector10 v = new Vector10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // scalar replaced 3075 long l = inlinedCallForcedToReturn(); 3076 lResult = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] 3077 + v.i0 + v.i1 + v.i2 + v.i3 + v.i4 + v.i5 + v.i6 + v.i7 + v.i8 + v.i9 + l; 3078 } 3079 3080 public long inlinedCallForcedToReturn() { // forced to return 43 3081 long cs = checkSum; 3082 dontinline_consumeAllMemory(); 3083 while (loopCount-- > 0) { 3084 targetIsInLoop = true; 3085 checkSum += checkSum % ++cs; 3086 } 3087 loopCount = 3; 3088 targetIsInLoop = false; 3089 return checkSum; 3090 } 3091 3092 public void dontinline_consumeAllMemory() { 3093 if (warmupDone) { 3094 consumeAllMemory(); 3095 } 3096 } 3097 3098 @Override 3099 public long getExpectedLResult() { 3100 long n = 10; 3101 return 2*n*(n+1)/2 + 43; 3102 } 3103 3104 @Override 3105 public void setUp() { 3106 super.setUp(); 3107 testMethodDepth = 2; 3108 loopCount = 3; 3109 } 3110 3111 public void warmupDone() { 3112 super.warmupDone(); 3113 msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE"); 3114 loopCount = Long.MAX_VALUE; // endless loop 3115 } 3116 3117 @Override 3118 public boolean shouldSkip() { 3119 // OOMEs because of realloc failures with DeoptimizeObjectsALot are too random. 3120 // And Graal currently doesn't support Force Early Return 3121 return super.shouldSkip() || 3122 !EliminateAllocations || 3123 // With ZGC or Shenandoah the OOME is not always thrown as expected 3124 ZGCIsSelected || 3125 ShenandoahGCIsSelected || 3126 DeoptimizeObjectsALot || 3127 UseJVMCICompiler; 3128 } 3129 } 3130 3131 ///////////////////////////////////////////////////////////////////////////// 3132 // 3133 // Get Instances of ReferenceType 3134 // 3135 ///////////////////////////////////////////////////////////////////////////// 3136 3137 /** 3138 * Check if instances of a type are found even if they are scalar replaced. To stress the 3139 * implementation a little more, the instances should be retrieved while the target is running. 3140 */ 3141 class EAGetInstancesOfReferenceType extends EATestCaseBaseDebugger { 3142 3143 public void runTestCase() throws Exception { 3144 printStack(env.targetMainThread); 3145 ReferenceType cls = ((ClassObjectReference)getField(testCase, "cls")).reflectedType(); 3146 msg("reflected type is " + cls); 3147 msg("resume"); 3148 env.vm().resume(); 3149 waitUntilTargetHasEnteredEndlessLoop(); 3150 // do this while thread is running! 3151 msg("Retrieve instances of " + cls.name()); 3152 List<ObjectReference> instances = cls.instances(10); 3153 Asserts.assertEQ(instances.size(), 3, "unexpected number of instances of " + cls.name()); 3154 // invariant: main thread is suspended at the end of the test case 3155 msg("suspend"); 3156 env.targetMainThread.suspend(); 3157 terminateEndlessLoop(); 3158 } 3159 } 3160 3161 class EAGetInstancesOfReferenceTypeTarget extends EATestCaseBaseTarget { 3162 3163 public long checkSum; 3164 3165 public static Class<LocalXYVal> cls = LocalXYVal.class; 3166 3167 public static class LocalXYVal { 3168 public int x, y; 3169 3170 public LocalXYVal(int x, int y) { 3171 this.x = x; this.y = y; 3172 } 3173 } 3174 3175 @Override 3176 public void dontinline_testMethod() { 3177 LocalXYVal p1 = new LocalXYVal(4, 2); 3178 LocalXYVal p2 = new LocalXYVal(5, 3); 3179 LocalXYVal p3 = new LocalXYVal(6, 4); 3180 dontinline_endlessLoop(); 3181 iResult = p1.x+p1.y + p2.x+p2.y + p3.x+p3.y; 3182 } 3183 3184 @Override 3185 public int getExpectedIResult() { 3186 return 6+8+10; 3187 } 3188 3189 @Override 3190 public void setUp() { 3191 super.setUp(); 3192 testMethodDepth = 2; 3193 loopCount = 3; 3194 } 3195 3196 public void warmupDone() { 3197 super.warmupDone(); 3198 msg("enter 'endless' loop by setting loopCount = Long.MAX_VALUE"); 3199 loopCount = Long.MAX_VALUE; // endless loop 3200 } 3201 } 3202 3203 3204 // End of test case collection 3205 ///////////////////////////////////////////////////////////////////////////// 3206 3207 ///////////////////////////////////////////////////////////////////////////// 3208 // Helper classes 3209 class XYVal { 3210 3211 public int x, y; 3212 3213 public XYVal(int x, int y) { 3214 this.x = x; 3215 this.y = y; 3216 } 3217 3218 /** 3219 * Note that we don't use a sync block here because javac would generate an synthetic exception 3220 * handler for the synchronized block that catches Throwable E, unlocks and throws E 3221 * again. The throw bytecode causes the BCEscapeAnalyzer to set the escape state to GlobalEscape 3222 * (see comment on exception handlers in BCEscapeAnalyzer::iterate_blocks()) 3223 */ 3224 public synchronized void dontinline_sync_method(EATestCaseBaseTarget target) { 3225 target.dontinline_brkpt(); 3226 } 3227 3228 /** 3229 * Just like {@link #dontinline_sync_method(EATestCaseBaseTarget)} but without the call to 3230 * {@link EATestCaseBaseTarget#dontinline_brkpt()}. 3231 */ 3232 public synchronized void dontinline_sync_method_no_brkpt(EATestCaseBaseTarget target) { 3233 } 3234 } 3235 3236 class Vector10 { 3237 int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9; 3238 public Vector10(int j0, int j1, int j2, int j3, int j4, int j5, int j6, int j7, int j8, int j9) { 3239 i0=j0; i1=j1; i2=j2; i3=j3; i4=j4; i5=j5; i6=j6; i7=j7; i8=j8; i9=j9; 3240 } 3241 } 3242 3243 class ILFDO { 3244 3245 public int i; 3246 public int i2; 3247 public long l; 3248 public long l2; 3249 public float f; 3250 public float f2; 3251 public double d; 3252 public double d2; 3253 public Long o; 3254 public Long o2; 3255 3256 public ILFDO(int i, 3257 int i2, 3258 long l, 3259 long l2, 3260 float f, 3261 float f2, 3262 double d, 3263 double d2, 3264 Long o, 3265 Long o2) { 3266 this.i = i; 3267 this.i2 = i2; 3268 this.l = l; 3269 this.l2 = l2; 3270 this.f = f; 3271 this.f2 = f2; 3272 this.d = d; 3273 this.d2 = d2; 3274 this.o = o; 3275 this.o2 = o2; 3276 } 3277 3278 }