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