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