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 }