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 }