Thu, 30 Apr 2015 12:06:39 -0700
8050486: compiler/rtm/ tests fail due to monitor deflation at safepoint synchronization
Reviewed-by: kvn, iignatyev
1.1 --- a/test/compiler/rtm/locking/TestRTMAbortRatio.java Thu Apr 30 11:47:53 2015 -0700 1.2 +++ b/test/compiler/rtm/locking/TestRTMAbortRatio.java Thu Apr 30 12:06:39 2015 -0700 1.3 @@ -126,10 +126,7 @@ 1.4 1.5 @Override 1.6 public String[] getMethodsToCompileNames() { 1.7 - return new String[] { 1.8 - getMethodWithLockName(), 1.9 - Unsafe.class.getName() + "::addressSize" 1.10 - }; 1.11 + return new String[] { getMethodWithLockName() }; 1.12 } 1.13 1.14 public void lock(boolean abort) { 1.15 @@ -147,10 +144,12 @@ 1.16 public static void main(String args[]) throws Throwable { 1.17 Asserts.assertGTE(args.length, 1, "One argument required."); 1.18 Test t = new Test(); 1.19 - if (Boolean.valueOf(args[0])) { 1.20 + boolean shouldBeInflated = Boolean.valueOf(args[0]); 1.21 + if (shouldBeInflated) { 1.22 AbortProvoker.inflateMonitor(t.monitor); 1.23 } 1.24 for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) { 1.25 + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); 1.26 t.lock(i >= Test.WARMUP_ITERATIONS); 1.27 } 1.28 }
2.1 --- a/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Thu Apr 30 11:47:53 2015 -0700 2.2 +++ b/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Thu Apr 30 12:06:39 2015 -0700 2.3 @@ -156,10 +156,7 @@ 2.4 2.5 @Override 2.6 public String[] getMethodsToCompileNames() { 2.7 - return new String[] { 2.8 - getMethodWithLockName(), 2.9 - sun.misc.Unsafe.class.getName() + "::forceAbort" 2.10 - }; 2.11 + return new String[] { getMethodWithLockName() }; 2.12 } 2.13 2.14 public void forceAbort(int a[], boolean abort) { 2.15 @@ -182,13 +179,15 @@ 2.16 public static void main(String args[]) throws Throwable { 2.17 Test t = new Test(); 2.18 2.19 - if (Boolean.valueOf(args[0])) { 2.20 + boolean shouldBeInflated = Boolean.valueOf(args[0]); 2.21 + if (shouldBeInflated) { 2.22 AbortProvoker.inflateMonitor(t.monitor); 2.23 } 2.24 2.25 int tmp[] = new int[1]; 2.26 2.27 for (int i = 0; i < Test.ITERATIONS; i++ ) { 2.28 + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); 2.29 if (i == Test.RANGE_CHECK_AT) { 2.30 t.forceAbort(new int[0], false); 2.31 } else {
3.1 --- a/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Thu Apr 30 11:47:53 2015 -0700 3.2 +++ b/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Thu Apr 30 12:06:39 2015 -0700 3.3 @@ -129,10 +129,7 @@ 3.4 3.5 @Override 3.6 public String[] getMethodsToCompileNames() { 3.7 - return new String[] { 3.8 - getMethodWithLockName(), 3.9 - sun.misc.Unsafe.class.getName() + "::addressSize" 3.10 - }; 3.11 + return new String[] { getMethodWithLockName() }; 3.12 } 3.13 3.14 public void forceAbort(boolean abort) { 3.15 @@ -150,11 +147,12 @@ 3.16 public static void main(String args[]) throws Throwable { 3.17 Asserts.assertGTE(args.length, 1, "One argument required."); 3.18 Test t = new Test(); 3.19 - 3.20 - if (Boolean.valueOf(args[0])) { 3.21 + boolean shouldBeInflated = Boolean.valueOf(args[0]); 3.22 + if (shouldBeInflated) { 3.23 AbortProvoker.inflateMonitor(t.monitor); 3.24 } 3.25 for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) { 3.26 + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); 3.27 t.forceAbort( 3.28 i == TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD); 3.29 }
4.1 --- a/test/compiler/rtm/locking/TestRTMLockingThreshold.java Thu Apr 30 11:47:53 2015 -0700 4.2 +++ b/test/compiler/rtm/locking/TestRTMLockingThreshold.java Thu Apr 30 12:06:39 2015 -0700 4.3 @@ -142,10 +142,7 @@ 4.4 4.5 @Override 4.6 public String[] getMethodsToCompileNames() { 4.7 - return new String[] { 4.8 - getMethodWithLockName(), 4.9 - sun.misc.Unsafe.class.getName() + "::addressSize" 4.10 - }; 4.11 + return new String[] { getMethodWithLockName() }; 4.12 } 4.13 4.14 public void lock(boolean abort) { 4.15 @@ -163,11 +160,12 @@ 4.16 public static void main(String args[]) throws Throwable { 4.17 Asserts.assertGTE(args.length, 1, "One argument required."); 4.18 Test t = new Test(); 4.19 - 4.20 - if (Boolean.valueOf(args[0])) { 4.21 + boolean shouldBeInflated = Boolean.valueOf(args[0]); 4.22 + if (shouldBeInflated) { 4.23 AbortProvoker.inflateMonitor(t.monitor); 4.24 } 4.25 for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) { 4.26 + AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated); 4.27 t.lock(i % 2 == 1); 4.28 } 4.29 }
5.1 --- a/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Thu Apr 30 11:47:53 2015 -0700 5.2 +++ b/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Thu Apr 30 12:06:39 2015 -0700 5.3 @@ -116,9 +116,7 @@ 5.4 5.5 @Override 5.6 public String[] getMethodsToCompileNames() { 5.7 - return new String[] { 5.8 - getMethodWithLockName() 5.9 - }; 5.10 + return new String[] { getMethodWithLockName() }; 5.11 } 5.12 5.13 public void lock() { 5.14 @@ -134,11 +132,13 @@ 5.15 public static void main(String args[]) throws Throwable { 5.16 Asserts.assertGTE(args.length, 1, "One argument required."); 5.17 Test test = new Test(); 5.18 - 5.19 - if (Boolean.valueOf(args[0])) { 5.20 + boolean shouldBeInflated = Boolean.valueOf(args[0]); 5.21 + if (shouldBeInflated) { 5.22 AbortProvoker.inflateMonitor(test.monitor); 5.23 } 5.24 for (long i = 0L; i < Test.TOTAL_ITERATIONS; i++) { 5.25 + AbortProvoker.verifyMonitorState(test.monitor, 5.26 + shouldBeInflated); 5.27 test.lock(); 5.28 } 5.29 }
6.1 --- a/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Thu Apr 30 11:47:53 2015 -0700 6.2 +++ b/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Thu Apr 30 12:06:39 2015 -0700 6.3 @@ -51,7 +51,7 @@ 6.4 * Compiled method invoked {@code AbortProvoker.DEFAULT_ITERATIONS} times before 6.5 * lock inflation and the same amount of times after inflation. 6.6 * As a result total locks count should be equal to 6.7 - * {@code 2*AbortProvoker.DEFAULT_ITERATIONS}. 6.8 + * {@code 2 * AbortProvoker.DEFAULT_ITERATIONS}. 6.9 * It is a pretty strict assertion which could fail if some retriable abort 6.10 * happened: it could be {@code AbortType.RETRIABLE} or 6.11 * {@code AbortType.MEM_CONFLICT}, but unfortunately abort can has both these 6.12 @@ -100,7 +100,6 @@ 6.13 } 6.14 6.15 public static class Test { 6.16 - 6.17 /** 6.18 * Usage: 6.19 * Test <provoker type> 6.20 @@ -112,10 +111,12 @@ 6.21 AbortProvoker provoker 6.22 = AbortType.lookup(Integer.valueOf(args[0])).provoker(); 6.23 for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) { 6.24 + AbortProvoker.verifyMonitorState(provoker, false /*deflated*/); 6.25 provoker.forceAbort(); 6.26 } 6.27 provoker.inflateMonitor(); 6.28 for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) { 6.29 + AbortProvoker.verifyMonitorState(provoker, true /*inflated*/); 6.30 provoker.forceAbort(); 6.31 } 6.32 }
7.1 --- a/test/compiler/testlibrary/rtm/AbortProvoker.java Thu Apr 30 11:47:53 2015 -0700 7.2 +++ b/test/compiler/testlibrary/rtm/AbortProvoker.java Thu Apr 30 12:06:39 2015 -0700 7.3 @@ -29,8 +29,7 @@ 7.4 import java.util.concurrent.CyclicBarrier; 7.5 7.6 import com.oracle.java.testlibrary.Asserts; 7.7 -import com.oracle.java.testlibrary.Utils; 7.8 -import sun.misc.Unsafe; 7.9 +import sun.hotspot.WhiteBox; 7.10 7.11 /** 7.12 * Base class for different transactional execution abortion 7.13 @@ -38,6 +37,9 @@ 7.14 */ 7.15 public abstract class AbortProvoker implements CompilableTest { 7.16 public static final long DEFAULT_ITERATIONS = 10000L; 7.17 + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 7.18 + @SuppressWarnings("unused") 7.19 + private static int sharedState = 0; 7.20 /** 7.21 * Inflates monitor associated with object {@code monitor}. 7.22 * Inflation is forced by entering the same monitor from 7.23 @@ -48,36 +50,76 @@ 7.24 * @throws Exception if something went wrong. 7.25 */ 7.26 public static Object inflateMonitor(Object monitor) throws Exception { 7.27 - Unsafe unsafe = Utils.getUnsafe(); 7.28 CyclicBarrier barrier = new CyclicBarrier(2); 7.29 7.30 Runnable inflatingRunnable = () -> { 7.31 - unsafe.monitorEnter(monitor); 7.32 - try { 7.33 - barrier.await(); 7.34 - barrier.await(); 7.35 - } catch (InterruptedException | BrokenBarrierException e) { 7.36 - throw new RuntimeException( 7.37 - "Synchronization issue occurred.", e); 7.38 - } finally { 7.39 - unsafe.monitorExit(monitor); 7.40 + synchronized (monitor) { 7.41 + try { 7.42 + barrier.await(); 7.43 + } catch (BrokenBarrierException | InterruptedException e) { 7.44 + throw new RuntimeException( 7.45 + "Synchronization issue occurred.", e); 7.46 + } 7.47 + try { 7.48 + monitor.wait(); 7.49 + } catch (InterruptedException e) { 7.50 + throw new AssertionError("The thread waiting on an" 7.51 + + " inflated monitor was interrupted, thus test" 7.52 + + " results may be incorrect.", e); 7.53 + } 7.54 } 7.55 }; 7.56 7.57 Thread t = new Thread(inflatingRunnable); 7.58 + t.setDaemon(true); 7.59 t.start(); 7.60 // Wait until thread t enters the monitor. 7.61 barrier.await(); 7.62 - // At this point monitor will be owned by thread t, 7.63 - // so our attempt to enter the same monitor will force 7.64 - // monitor inflation. 7.65 - Asserts.assertFalse(unsafe.tryMonitorEnter(monitor), 7.66 - "Not supposed to enter the monitor first"); 7.67 - barrier.await(); 7.68 - t.join(); 7.69 + synchronized (monitor) { 7.70 + // At this point thread t is already waiting on the monitor. 7.71 + // Modifying static field just to avoid lock's elimination. 7.72 + sharedState++; 7.73 + } 7.74 + verifyMonitorState(monitor, true /* inflated */); 7.75 return monitor; 7.76 } 7.77 7.78 + /** 7.79 + * Verifies that {@code monitor} is a stack-lock or inflated lock depending 7.80 + * on {@code shouldBeInflated} value. If {@code monitor} is inflated while 7.81 + * it is expected that it should be a stack-lock, then this method attempts 7.82 + * to deflate it by forcing a safepoint and then verifies the state once 7.83 + * again. 7.84 + * 7.85 + * @param monitor monitor to be verified. 7.86 + * @param shouldBeInflated flag indicating whether or not monitor is 7.87 + * expected to be inflated. 7.88 + * @throws RuntimeException if the {@code monitor} in a wrong state. 7.89 + */ 7.90 + public static void verifyMonitorState(Object monitor, 7.91 + boolean shouldBeInflated) { 7.92 + if (!shouldBeInflated && WHITE_BOX.isMonitorInflated(monitor)) { 7.93 + WHITE_BOX.forceSafepoint(); 7.94 + } 7.95 + Asserts.assertEQ(WHITE_BOX.isMonitorInflated(monitor), shouldBeInflated, 7.96 + "Monitor in a wrong state."); 7.97 + } 7.98 + /** 7.99 + * Verifies that monitor used by the {@code provoker} is a stack-lock or 7.100 + * inflated lock depending on {@code shouldBeInflated} value. If such 7.101 + * monitor is inflated while it is expected that it should be a stack-lock, 7.102 + * then this method attempts to deflate it by forcing a safepoint and then 7.103 + * verifies the state once again. 7.104 + * 7.105 + * @param provoker AbortProvoker whose monitor's state should be verified. 7.106 + * @param shouldBeInflated flag indicating whether or not monitor is 7.107 + * expected to be inflated. 7.108 + * @throws RuntimeException if the {@code monitor} in a wrong state. 7.109 + */ 7.110 + public static void verifyMonitorState(AbortProvoker provoker, 7.111 + boolean shouldBeInflated) { 7.112 + verifyMonitorState(provoker.monitor, shouldBeInflated); 7.113 + } 7.114 7.115 /** 7.116 * Get instance of specified AbortProvoker, inflate associated monitor 7.117 @@ -120,6 +162,7 @@ 7.118 } 7.119 7.120 for (long i = 0; i < iterations; i++) { 7.121 + AbortProvoker.verifyMonitorState(provoker, monitorShouldBeInflated); 7.122 provoker.forceAbort(); 7.123 } 7.124 }
8.1 --- a/test/compiler/testlibrary/rtm/BusyLock.java Thu Apr 30 11:47:53 2015 -0700 8.2 +++ b/test/compiler/testlibrary/rtm/BusyLock.java Thu Apr 30 12:06:39 2015 -0700 8.3 @@ -77,7 +77,7 @@ 8.4 } 8.5 } 8.6 8.7 - public void test() { 8.8 + public void syncAndTest() { 8.9 try { 8.10 barrier.await(); 8.11 // wait until monitor is locked by a ::run method 8.12 @@ -85,6 +85,10 @@ 8.13 } catch (InterruptedException | BrokenBarrierException e) { 8.14 throw new RuntimeException("Synchronization error happened.", e); 8.15 } 8.16 + test(); 8.17 + } 8.18 + 8.19 + public void test() { 8.20 synchronized(monitor) { 8.21 BusyLock.field++; 8.22 } 8.23 @@ -130,7 +134,7 @@ 8.24 8.25 Thread t = new Thread(busyLock); 8.26 t.start(); 8.27 - busyLock.test(); 8.28 + busyLock.syncAndTest(); 8.29 t.join(); 8.30 } 8.31 }
9.1 --- a/test/compiler/testlibrary/rtm/MemoryConflictProvoker.java Thu Apr 30 11:47:53 2015 -0700 9.2 +++ b/test/compiler/testlibrary/rtm/MemoryConflictProvoker.java Thu Apr 30 12:06:39 2015 -0700 9.3 @@ -69,11 +69,6 @@ 9.4 * Accesses and modifies memory region from within the transaction. 9.5 */ 9.6 public void transactionalRegion() { 9.7 - try { 9.8 - barrier.await(); 9.9 - } catch (InterruptedException | BrokenBarrierException e) { 9.10 - throw new RuntimeException(e); 9.11 - } 9.12 for (int i = 0; i < MemoryConflictProvoker.INNER_ITERATIONS; i++) { 9.13 synchronized(monitor) { 9.14 MemoryConflictProvoker.field--; 9.15 @@ -86,6 +81,11 @@ 9.16 try { 9.17 Thread t = new Thread(conflictingThread); 9.18 t.start(); 9.19 + try { 9.20 + barrier.await(); 9.21 + } catch (InterruptedException | BrokenBarrierException e) { 9.22 + throw new RuntimeException(e); 9.23 + } 9.24 transactionalRegion(); 9.25 t.join(); 9.26 } catch (Exception e) {
10.1 --- a/test/compiler/testlibrary/rtm/RTMTestBase.java Thu Apr 30 11:47:53 2015 -0700 10.2 +++ b/test/compiler/testlibrary/rtm/RTMTestBase.java Thu Apr 30 12:06:39 2015 -0700 10.3 @@ -238,10 +238,10 @@ 10.4 String[] filteredVMOpts = Utils.getFilteredTestJavaOpts(filters); 10.5 Collections.addAll(finalVMOpts, filteredVMOpts); 10.6 Collections.addAll(finalVMOpts, "-Xcomp", "-server", 10.7 - "-XX:-TieredCompilation", 10.8 + "-XX:-TieredCompilation", "-XX:+UseRTMLocking", 10.9 CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS, 10.10 CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS, 10.11 - "-XX:+UseRTMLocking"); 10.12 + "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI"); 10.13 10.14 if (test != null) { 10.15 for (String method : test.getMethodsToCompileNames()) {