1 /*
   2  * Copyright (c) 2019 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  * @test
  26  * @bug 8227745
  27  * @summary Test JVMTI's GetOwnedMonitorInfo with scalar replaced objects and eliminated locks on stack (optimizations based on escape analysis).
  28  * @requires (vm.compMode != "Xcomp" & vm.compiler2.enabled)
  29  * @library /test/lib
  30  * @compile GetOwnedMonitorInfoWithEATest.java
  31  * @run main/othervm/native
  32  *                  -agentlib:GetOwnedMonitorInfoWithEATest
  33  *                  -XX:+UnlockDiagnosticVMOptions
  34  *                  -Xms32m -Xmx32m
  35  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  36  *                  -XX:+PrintCompilation
  37  *                  -XX:+PrintInlining
  38  *                  -XX:-TieredCompilation
  39  *                  -Xbatch
  40  *                  -XX:CICompilerCount=1
  41  *                  -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
  42  *                  GetOwnedMonitorInfoWithEATest
  43  * @run main/othervm/native
  44  *                  -agentlib:GetOwnedMonitorInfoWithEATest
  45  *                  -XX:+UnlockDiagnosticVMOptions
  46  *                  -Xms32m -Xmx32m
  47  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  48  *                  -XX:+PrintCompilation
  49  *                  -XX:+PrintInlining
  50  *                  -XX:-TieredCompilation
  51  *                  -Xbatch
  52  *                  -XX:CICompilerCount=1
  53  *                  -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:-EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking -XX:-UseOptoBiasInlining
  54  *                  GetOwnedMonitorInfoWithEATest
  55  * @run main/othervm/native
  56  *                  -agentlib:GetOwnedMonitorInfoWithEATest
  57  *                  -XX:+UnlockDiagnosticVMOptions
  58  *                  -Xms32m -Xmx32m
  59  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  60  *                  -XX:+PrintCompilation
  61  *                  -XX:+PrintInlining
  62  *                  -XX:-TieredCompilation
  63  *                  -Xbatch
  64  *                  -XX:CICompilerCount=1
  65  *                  -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
  66  *                  GetOwnedMonitorInfoWithEATest
  67  * @run main/othervm/native
  68  *                  -agentlib:GetOwnedMonitorInfoWithEATest
  69  *                  -XX:+UnlockDiagnosticVMOptions
  70  *                  -Xms32m -Xmx32m
  71  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  72  *                  -XX:+PrintCompilation
  73  *                  -XX:+PrintInlining
  74  *                  -XX:-TieredCompilation
  75  *                  -Xbatch
  76  *                  -XX:CICompilerCount=1
  77  *                  -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:+UseBiasedLocking
  78  *                  GetOwnedMonitorInfoWithEATest
  79  * @run main/othervm/native
  80  *                  -agentlib:GetOwnedMonitorInfoWithEATest
  81  *                  -XX:+UnlockDiagnosticVMOptions
  82  *                  -Xms32m -Xmx32m
  83  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  84  *                  -XX:+PrintCompilation
  85  *                  -XX:+PrintInlining
  86  *                  -XX:-TieredCompilation
  87  *                  -Xbatch
  88  *                  -XX:CICompilerCount=1
  89  *                  -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
  90  *                  GetOwnedMonitorInfoWithEATest
  91  * @run main/othervm/native
  92  *                  -agentlib:GetOwnedMonitorInfoWithEATest
  93  *                  -XX:+UnlockDiagnosticVMOptions
  94  *                  -Xms32m -Xmx32m
  95  *                  -XX:CompileCommand=dontinline,*::dontinline_*
  96  *                  -XX:+PrintCompilation
  97  *                  -XX:+PrintInlining
  98  *                  -XX:-TieredCompilation
  99  *                  -Xbatch
 100  *                  -XX:CICompilerCount=1
 101  *                  -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
 102  *                  GetOwnedMonitorInfoWithEATest
 103  * @run main/othervm/native
 104  *                  -agentlib:GetOwnedMonitorInfoWithEATest
 105  *                  -XX:+UnlockDiagnosticVMOptions
 106  *                  -Xms32m -Xmx32m
 107  *                  -XX:CompileCommand=dontinline,*::dontinline_*
 108  *                  -XX:+PrintCompilation
 109  *                  -XX:+PrintInlining
 110  *                  -XX:-TieredCompilation
 111  *                  -Xbatch
 112  *                  -XX:CICompilerCount=1
 113  *                  -XX:-DoEscapeAnalysis -XX:-EliminateAllocations -XX:+EliminateLocks -XX:+EliminateNestedLocks -XX:-UseBiasedLocking
 114  *                  GetOwnedMonitorInfoWithEATest
 115  */
 116 
 117 import jdk.test.lib.Asserts;
 118 
 119 public class GetOwnedMonitorInfoWithEATest {
 120 
 121     public static final int COMPILE_THRESHOLD = 20000;
 122 
 123     /**
 124      * Native wrapper arround JVMTI's GetOwnedMonitorInfo().
 125      * @param t The thread for which the owned monitors information should be retrieved.
 126      * @param ownedMonitors Array filled in by the call with the objects associated 
 127      *        with the monitors owned by the given thread.
 128      * @param depths Per owned monitor the depth of the frame were it was locked.
 129      *        Filled in by the call
 130      * @return Number of monitors owned by the given thread.
 131      */
 132     public static native int getOwnedMonitorInfo(Thread t, Object[] ownedMonitors);
 133 
 134     public static void main(String[] args) throws Exception {
 135         new GetOwnedMonitorInfoWithEATest().runTest();
 136     }
 137 
 138     public void runTest() throws Exception {
 139         new TestCase_1().run();
 140         new TestCase_2().run();
 141     }
 142 
 143     public static abstract class TestCaseBase implements Runnable {
 144 
 145         public long checkSum;
 146         public boolean doLoop;
 147         public volatile long loopCount;
 148         public volatile boolean targetIsInLoop;
 149 
 150         public void run() {
 151             try {
 152                 msgHL("Executing test case " + getClass().getName());
 153                 warmUp();
 154                 runTest();
 155             } catch (Exception e) {
 156                 Asserts.fail("Unexpected Exception", e);
 157             }
 158         }
 159 
 160         public void warmUp() {
 161             int callCount = COMPILE_THRESHOLD + 1000;
 162             doLoop = true;
 163             while (callCount-- > 0) {
 164                 dontinline_testMethod();
 165             }
 166         }
 167 
 168         public abstract void runTest() throws Exception;
 169         public abstract void dontinline_testMethod();
 170 
 171         public long dontinline_endlessLoop() {
 172             long cs = checkSum;
 173             while (doLoop && loopCount-- > 0) {
 174                 targetIsInLoop = true;
 175                 checkSum += checkSum % ++cs;
 176             }
 177             loopCount = 3;
 178             targetIsInLoop = false;
 179             return checkSum;
 180         }
 181 
 182         public void waitUntilTargetThreadHasEnteredEndlessLoop() throws Exception {
 183             while(!targetIsInLoop) {
 184                 msg("Target has not yet entered the loop. Sleep 200ms.");
 185                 try { Thread.sleep(200); } catch (InterruptedException e) { /*ignore */ }
 186             }
 187             msg("Target has entered the loop.");
 188         }
 189 
 190         public void terminateEndlessLoop() throws Exception {
 191             msg("Terminate endless loop");
 192             do {
 193                 doLoop = false;
 194             } while(targetIsInLoop);
 195         }
 196 
 197         public void msg(String m) {
 198             System.out.println();
 199             System.out.println("### " + m);
 200             System.out.println();
 201         }
 202         
 203         public void msgHL(String m) {
 204             System.out.println();
 205             System.out.println("#####################################################");
 206             System.out.println("### " + m);
 207             System.out.println("###");
 208             System.out.println();
 209         }
 210     }
 211 
 212     /**
 213      * Starts target thread T and then queries monitor information for T using JVMTI's GetOwnedMonitorInfo().
 214      * The jit compiled method {@link #dontinline_testMethod()} has scalar replaced objects with eliminated (nested) locking in scope when
 215      * the monitor information is retrieved.
 216      */
 217     public static class TestCase_1 extends TestCaseBase {
 218 
 219         public void runTest() throws Exception {
 220             loopCount = 1L << 62; // endless loop
 221             Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread");
 222             t1.start();
 223             try {
 224                 waitUntilTargetThreadHasEnteredEndlessLoop();
 225                 int expectedMonitorCount = 1;
 226                 int resultSize = expectedMonitorCount + 3;
 227                 Object[] ownedMonitors = new Object[resultSize];
 228                 msg("Get monitor info");
 229                 int monitorCount = getOwnedMonitorInfo(t1, ownedMonitors);
 230                 terminateEndlessLoop();
 231                 t1.join();
 232                 Asserts.assertGreaterThanOrEqual(monitorCount, 0, "getOwnedMonitorsFor() call failed");
 233                 msg("Monitor info:");
 234                 for (int i = 0; i < monitorCount; i++) {
 235                     System.out.println(i + ": cls=" + (ownedMonitors[i] != null ? ownedMonitors[i].getClass() : null));
 236                 }
 237                 Asserts.assertEQ(monitorCount, expectedMonitorCount, "unexpected monitor count returned by getOwnedMonitorsFor()");
 238                 Asserts.assertNotNull(ownedMonitors[0]);
 239                 Asserts.assertSame(ownedMonitors[0].getClass(), LockCls.class);
 240             } finally {
 241                 terminateEndlessLoop();
 242                 t1.join();
 243             }
 244         }
 245 
 246         public void dontinline_testMethod() {
 247             LockCls l1 = new LockCls();        // to be scalar replaced
 248             synchronized (l1) {
 249                 inlinedTestMethodWithNestedLocking(l1);
 250             }
 251         }
 252 
 253         public void inlinedTestMethodWithNestedLocking(LockCls l1) {
 254             synchronized (l1) {              // nested
 255                 dontinline_endlessLoop();
 256             }
 257         }
 258     }
 259 
 260     /**
 261      * Similar to {@link TestCase_1}. Additionally the target thread T has got eliminated locking
 262      * for a synchronized method of a different type {@linkplain LockCls2}.
 263      */
 264     public static class TestCase_2 extends TestCaseBase {
 265 
 266         public void runTest() throws Exception {
 267             loopCount = 1L << 62; // endless loop
 268             Thread t1 = new Thread(() -> dontinline_testMethod(), "Target Thread");
 269             t1.start();
 270             try {
 271                 waitUntilTargetThreadHasEnteredEndlessLoop();
 272                 int expectedMonitorCount = 2;
 273                 int resultSize = expectedMonitorCount + 3;
 274                 Object[] ownedMonitors = new Object[resultSize];
 275                 msg("Get monitor info");
 276                 int monitorCount = getOwnedMonitorInfo(t1, ownedMonitors);
 277                 terminateEndlessLoop();
 278                 t1.join();
 279                 Asserts.assertGreaterThanOrEqual(monitorCount, 0, "getOwnedMonitorsFor() call failed");
 280                 msg("Monitor info:");
 281                 for (int i = 0; i < monitorCount; i++) {
 282                     System.out.println(i + ": cls=" + (ownedMonitors[i] != null ? ownedMonitors[i].getClass() : null));
 283                 }
 284                 Asserts.assertEQ(monitorCount, expectedMonitorCount, "unexpected monitor count returned by getOwnedMonitorsFor()");
 285                 Asserts.assertNotNull(ownedMonitors[0]);
 286                 Asserts.assertSame(ownedMonitors[0].getClass(), LockCls2.class);
 287 
 288                 Asserts.assertNotNull(ownedMonitors[1]);
 289                 Asserts.assertSame(ownedMonitors[1].getClass(), LockCls.class);
 290             } finally {
 291                 terminateEndlessLoop();
 292                 t1.join();
 293             }
 294         }
 295 
 296         public void dontinline_testMethod() {
 297             LockCls l1 = new LockCls();
 298             synchronized (l1) {
 299                 inlinedTestMethodWithNestedLocking(l1);
 300             }
 301         }
 302 
 303         public void inlinedTestMethodWithNestedLocking(LockCls l1) {
 304             synchronized (l1) {
 305                 dontinline_testMethod2();
 306             }
 307         }
 308 
 309         public void dontinline_testMethod2() {
 310             // Call synchronized method. Receiver of the call will be scalar replaced,
 311             // and locking will be eliminated. Here we use a different type.
 312             new LockCls2().inline_synchronized_testMethod(this);
 313         } 
 314     }
 315 
 316     public static class LockCls {
 317     }
 318 
 319     public static class LockCls2 {
 320         public synchronized void inline_synchronized_testMethod(TestCaseBase testCase) {
 321             testCase.dontinline_endlessLoop();
 322         }
 323     }
 324 }