1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. 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 8031320 28 * @summary Verify that if we use RTMDeopt, then deoptimization 29 * caused by reason other then rtm_state_change will reset 30 * method's RTM state. And if we don't use RTMDeopt, then 31 * RTM state remain the same after such deoptimization. 32 * @library /testlibrary /testlibrary/whitebox /compiler/testlibrary 33 * @build TestRTMAfterNonRTMDeopt 34 * @run main/othervm/bootclasspath -XX:+UnlockDiagnosticVMOptions 35 * -XX:+WhiteBoxAPI TestRTMAfterNonRTMDeopt 36 */ 37 38 import java.util.List; 39 import com.oracle.java.testlibrary.*; 40 import com.oracle.java.testlibrary.cli.CommandLineOptionTest; 41 import com.oracle.java.testlibrary.cli.predicate.AndPredicate; 42 import rtm.*; 43 import rtm.predicate.SupportedCPU; 44 import rtm.predicate.SupportedVM; 45 import sun.misc.Unsafe; 46 47 /** 48 * To verify that with +UseRTMDeopt method's RTM state will be 49 * changed to ProfileRTM on deoptimization unrelated to 50 * rtm_state_change following sequence of events is used: 51 * <pre> 52 * 53 * rtm state ^ 54 * | 55 * UseRTM | ******| ****** 56 * | | 57 * ProfileRTM |******| |*****| 58 * | | | | 59 * 0-------|-----|-----|---------------------> time 60 * | | \ force abort 61 * | | 62 * | \ force deoptimization 63 * | 64 * \ force xabort 65 * </pre> 66 * When xabort is forced by native method call method should 67 * change it's state to UseRTM, because we use RTMAbortRatio=100 68 * and low RTMLockingThreshold, so at this point actual abort 69 * ratio will be below 100% and there should be enough lock 70 * attempts to recompile method without RTM profiling. 71 */ 72 public class TestRTMAfterNonRTMDeopt extends CommandLineOptionTest { 73 private static final int ABORT_THRESHOLD = 1000; 74 private static final String RANGE_CHECK = "range_check"; 75 76 private TestRTMAfterNonRTMDeopt() { 77 super(new AndPredicate(new SupportedCPU(), new SupportedVM())); 78 } 79 80 @Override 81 protected void runTestCases() throws Throwable { 82 verifyRTMAfterDeopt(false, false); 83 verifyRTMAfterDeopt(true, false); 84 85 verifyRTMAfterDeopt(false, true); 86 verifyRTMAfterDeopt(true, true); 87 } 88 89 private void verifyRTMAfterDeopt(boolean useStackLock, 90 boolean useRTMDeopt) throws Throwable { 91 CompilableTest test = new Test(); 92 String logFile = String.format("rtm_%s_stack_lock_%s_deopt.xml", 93 (useStackLock ? "use" : "no"), (useRTMDeopt ? "use" : "no")); 94 95 OutputAnalyzer outputAnalyzer = RTMTestBase.executeRTMTest( 96 logFile, 97 test, 98 "-XX:CompileThreshold=1", 99 CommandLineOptionTest.prepareBooleanFlag("UseRTMForStackLocks", 100 useStackLock), 101 CommandLineOptionTest.prepareBooleanFlag("UseRTMDeopt", 102 useRTMDeopt), 103 "-XX:RTMAbortRatio=100", 104 CommandLineOptionTest.prepareNumericFlag("RTMAbortThreshold", 105 TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD), 106 CommandLineOptionTest.prepareNumericFlag("RTMLockingThreshold", 107 TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD / 2L), 108 "-XX:RTMTotalCountIncrRate=1", 109 "-XX:+PrintPreciseRTMLockingStatistics", 110 Test.class.getName(), 111 Boolean.toString(!useStackLock) 112 ); 113 114 outputAnalyzer.shouldHaveExitValue(0); 115 116 int traps = RTMTestBase.firedRTMStateChangeTraps(logFile); 117 118 if (useRTMDeopt) { 119 Asserts.assertEQ(traps, 2, "Two uncommon traps with " 120 + "reason rtm_state_change should be fired."); 121 } else { 122 Asserts.assertEQ(traps, 0, "No uncommon traps with " 123 + "reason rtm_state_change should be fired."); 124 } 125 126 int rangeCheckTraps = RTMTestBase.firedUncommonTraps(logFile, 127 TestRTMAfterNonRTMDeopt.RANGE_CHECK); 128 129 Asserts.assertEQ(rangeCheckTraps, 1, 130 "One range_check uncommon trap should be fired."); 131 132 List<RTMLockingStatistics> statistics = RTMLockingStatistics.fromString( 133 test.getMethodWithLockName(), outputAnalyzer.getOutput()); 134 135 int expectedStatEntries = (useRTMDeopt ? 4 : 2); 136 137 Asserts.assertEQ(statistics.size(), expectedStatEntries, 138 String.format("VM output should contain %d RTM locking " 139 + "statistics entries.", expectedStatEntries)); 140 } 141 142 public static class Test implements CompilableTest { 143 // Following field have to be static in order to avoid escape analysis. 144 @SuppressWarnings("UnsuedDeclaration") 145 private static int field = 0; 146 private static final int ITERATIONS = 10000; 147 private static final int RANGE_CHECK_AT = ITERATIONS / 2; 148 private static final Unsafe UNSAFE = Utils.getUnsafe(); 149 private final Object monitor = new Object(); 150 151 @Override 152 public String getMethodWithLockName() { 153 return this.getClass().getName() + "::forceAbort"; 154 } 155 156 @Override 157 public String[] getMethodsToCompileNames() { 158 return new String[] { 159 getMethodWithLockName(), 160 sun.misc.Unsafe.class.getName() + "::forceAbort" 161 }; 162 } 163 164 public void forceAbort(int a[], boolean abort) { 165 try { 166 synchronized(monitor) { 167 a[0]++; 168 if (abort) { 169 Test.field = Test.UNSAFE.addressSize(); 170 } 171 } 172 } catch (Throwable t) { 173 // suppress any throwables 174 } 175 } 176 177 /** 178 * Usage: 179 * Test <inflate monitor> 180 */ 181 public static void main(String args[]) throws Throwable { 182 Test t = new Test(); 183 184 if (Boolean.valueOf(args[0])) { 185 AbortProvoker.inflateMonitor(t.monitor); 186 } 187 188 int tmp[] = new int[1]; 189 190 for (int i = 0; i < Test.ITERATIONS; i++ ) { 191 if (i == Test.RANGE_CHECK_AT) { 192 t.forceAbort(new int[0], false); 193 } else { 194 boolean isThreshold 195 = (i == TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD); 196 boolean isThresholdPlusRange 197 = (i == TestRTMAfterNonRTMDeopt.ABORT_THRESHOLD 198 + Test.RANGE_CHECK_AT); 199 t.forceAbort(tmp, isThreshold || isThresholdPlusRange); 200 } 201 } 202 } 203 } 204 205 public static void main(String args[]) throws Throwable { 206 new TestRTMAfterNonRTMDeopt().test(); 207 } 208 } 209