1 /* 2 * Copyright Amazon.com Inc. 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 * @test TestOnSpinWaitAArch64 26 * @summary Checks that java.lang.Thread.onSpinWait is intrinsified with instructions specified with '-XX:OnSpinWaitInst' and '-XX:OnSpinWaitInstCount' 27 * @bug 8186670 28 * @library /test/lib 29 * 30 * @requires vm.flagless 31 * @requires os.arch=="aarch64" 32 * 33 * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c2 nop 7 34 * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c2 isb 3 35 * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c2 yield 1 36 * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c1 nop 7 37 * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c1 isb 3 38 * @run driver compiler.onSpinWait.TestOnSpinWaitAArch64 c1 yield 39 */ 40 41 package compiler.onSpinWait; 42 43 import java.util.ArrayList; 44 import java.util.Iterator; 45 import java.util.ListIterator; 46 import jdk.test.lib.process.OutputAnalyzer; 47 import jdk.test.lib.process.ProcessTools; 48 49 public class TestOnSpinWaitAArch64 { 50 public static void main(String[] args) throws Exception { 51 String compiler = args[0]; 52 String spinWaitInst = args[1]; 53 String spinWaitInstCount = (args.length == 3) ? args[2] : "1"; 54 ArrayList<String> command = new ArrayList<String>(); 55 command.add("-XX:+IgnoreUnrecognizedVMOptions"); 56 command.add("-showversion"); 57 command.add("-XX:-BackgroundCompilation"); 58 command.add("-XX:+UnlockDiagnosticVMOptions"); 59 command.add("-XX:+PrintAssembly"); 60 if (compiler.equals("c2")) { 61 command.add("-XX:-TieredCompilation"); 62 } else if (compiler.equals("c1")) { 63 command.add("-XX:+TieredCompilation"); 64 command.add("-XX:TieredStopAtLevel=1"); 65 } else { 66 throw new RuntimeException("Unknown compiler: " + compiler); 67 } 68 command.add("-Xbatch"); 69 command.add("-XX:OnSpinWaitInst=" + spinWaitInst); 70 command.add("-XX:OnSpinWaitInstCount=" + spinWaitInstCount); 71 command.add("-XX:CompileCommand=compileonly," + Launcher.class.getName() + "::" + "test"); 72 command.add(Launcher.class.getName()); 73 74 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(command); 75 76 OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); 77 78 analyzer.shouldHaveExitValue(0); 79 80 System.out.println(analyzer.getOutput()); 81 82 checkOutput(analyzer, spinWaitInst, Integer.parseInt(spinWaitInstCount)); 83 } 84 85 private static String getSpinWaitInstHex(String spinWaitInst) { 86 if ("nop".equals(spinWaitInst)) { 87 return "1f20 03d5"; 88 } else if ("isb".equals(spinWaitInst)) { 89 return "df3f 03d5"; 90 } else if ("yield".equals(spinWaitInst)) { 91 return "3f20 03d5"; 92 } else { 93 throw new RuntimeException("Unknown spin wait instruction: " + spinWaitInst); 94 } 95 } 96 97 private static void addInstrs(String line, ArrayList<String> instrs) { 98 for (String instr : line.split("\\|")) { 99 instrs.add(instr.trim()); 100 } 101 } 102 103 // The expected output of PrintAssembly for example for a spin wait with three NOPs: 104 // 105 // # {method} {0x0000ffff6ac00370} 'test' '()V' in 'compiler/onSpinWait/TestOnSpinWaitAArch64$Launcher' 106 // # [sp+0x40] (sp of caller) 107 // 0x0000ffff9d557680: 1f20 03d5 | e953 40d1 | 3f01 00f9 | ff03 01d1 | fd7b 03a9 | 1f20 03d5 | 1f20 03d5 108 // 109 // 0x0000ffff9d5576ac: ;*invokestatic onSpinWait {reexecute=0 rethrow=0 return_oop=0} 110 // ; - compiler.onSpinWait.TestOnSpinWaitAArch64$Launcher::test@0 (line 161) 111 // 0x0000ffff9d5576ac: 1f20 03d5 | fd7b 43a9 | ff03 0191 112 // 113 // The checkOutput method adds hex instructions before 'invokestatic onSpinWait' and from the line after 114 // it to a list. The list is traversed from the end to count spin wait instructions. 115 // 116 // If JVM finds the hsdis library the output is like: 117 // 118 // # {method} {0x0000ffff63000370} 'test' '()V' in 'compiler/onSpinWait/TestOnSpinWaitAArch64$Launcher' 119 // # [sp+0x20] (sp of caller) 120 // 0x0000ffffa409da80: nop 121 // 0x0000ffffa409da84: sub sp, sp, #0x20 122 // 0x0000ffffa409da88: stp x29, x30, [sp, #16] ;*synchronization entry 123 // ; - compiler.onSpinWait.TestOnSpinWaitAArch64$Launcher::test@-1 (line 187) 124 // 0x0000ffffa409da8c: nop 125 // 0x0000ffffa409da90: nop 126 // 0x0000ffffa409da94: nop 127 // 0x0000ffffa409da98: nop 128 // 0x0000ffffa409da9c: nop 129 // 0x0000ffffa409daa0: nop 130 // 0x0000ffffa409daa4: nop ;*invokestatic onSpinWait {reexecute=0 rethrow=0 return_oop=0} 131 // ; - compiler.onSpinWait.TestOnSpinWaitAArch64$Launcher::test@0 (line 187) 132 private static void checkOutput(OutputAnalyzer output, String spinWaitInst, int spinWaitInstCount) { 133 Iterator<String> iter = output.asLines().listIterator(); 134 135 String match = skipTo(iter, "'test' '()V' in 'compiler/onSpinWait/TestOnSpinWaitAArch64$Launcher'"); 136 if (match == null) { 137 throw new RuntimeException("Missing compiler output for the method compiler.onSpinWait.TestOnSpinWaitAArch64$Launcher::test"); 138 } 139 140 ArrayList<String> instrs = new ArrayList<String>(); 141 String line = null; 142 boolean hasHexInstInOutput = false; 143 while (iter.hasNext()) { 144 line = iter.next(); 145 if (line.contains("*invokestatic onSpinWait")) { 146 break; 147 } 148 if (!hasHexInstInOutput) { 149 hasHexInstInOutput = line.contains("|"); 150 } 151 if (line.contains("0x") && !line.contains(";")) { 152 addInstrs(line, instrs); 153 } 154 } 155 156 if (!iter.hasNext() || !iter.next().contains("- compiler.onSpinWait.TestOnSpinWaitAArch64$Launcher::test@0") || !iter.hasNext()) { 157 throw new RuntimeException("Missing compiler output for Thread.onSpinWait intrinsic"); 158 } 159 160 String strToSearch = null; 161 if (!hasHexInstInOutput) { 162 instrs.add(line.split(";")[0].trim()); 163 strToSearch = spinWaitInst; 164 } else { 165 line = iter.next(); 166 if (!line.contains("0x") || line.contains(";")) { 167 throw new RuntimeException("Expected hex instructions"); 168 } 169 170 addInstrs(line, instrs); 171 strToSearch = getSpinWaitInstHex(spinWaitInst); 172 } 173 174 int foundInstCount = 0; 175 176 ListIterator<String> instrReverseIter = instrs.listIterator(instrs.size()); 177 while (instrReverseIter.hasPrevious()) { 178 if (instrReverseIter.previous().endsWith(strToSearch)) { 179 foundInstCount = 1; 180 break; 181 } 182 } 183 184 while (instrReverseIter.hasPrevious()) { 185 if (!instrReverseIter.previous().endsWith(strToSearch)) { 186 break; 187 } 188 ++foundInstCount; 189 } 190 191 if (foundInstCount != spinWaitInstCount) { 192 throw new RuntimeException("Wrong instruction " + strToSearch + " count " + foundInstCount + "!\n -- expecting " + spinWaitInstCount); 193 } 194 } 195 196 private static String skipTo(Iterator<String> iter, String substring) { 197 while (iter.hasNext()) { 198 String nextLine = iter.next(); 199 if (nextLine.contains(substring)) { 200 return nextLine; 201 } 202 } 203 return null; 204 } 205 206 static class Launcher { 207 public static void main(final String[] args) throws Exception { 208 int end = 20_000; 209 210 for (int i=0; i < end; i++) { 211 test(); 212 } 213 } 214 static void test() { 215 java.lang.Thread.onSpinWait(); 216 } 217 } 218 }