1 /* 2 * Copyright (c) 2014, 2015, 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 import jdk.test.lib.Asserts; 26 import jdk.test.lib.Platform; 27 import jdk.test.lib.Utils; 28 import sun.hotspot.code.NMethod; 29 import sun.hotspot.cpuinfo.CPUInfo; 30 31 import java.lang.invoke.MethodHandle; 32 import java.lang.invoke.MethodType; 33 import java.lang.reflect.Executable; 34 import java.lang.reflect.Method; 35 import java.util.concurrent.Callable; 36 import java.util.function.Function; 37 import compiler.whitebox.CompilerWhiteBoxTest; 38 39 public class BmiIntrinsicBase extends CompilerWhiteBoxTest { 40 41 protected BmiIntrinsicBase(BmiTestCase testCase) { 42 super(testCase); 43 } 44 45 public static void verifyTestCase(Function<Method, BmiTestCase> constructor, Method... methods) throws Exception { 46 for (Method method : methods) { 47 new BmiIntrinsicBase(constructor.apply(method)).test(); 48 } 49 } 50 51 @Override 52 protected void test() throws Exception { 53 BmiTestCase bmiTestCase = (BmiTestCase) testCase; 54 55 if (!(Platform.isX86() || Platform.isX64())) { 56 System.out.println("Unsupported platform, test SKIPPED"); 57 return; 58 } 59 60 if (!Platform.isServer()) { 61 System.out.println("Not server VM, test SKIPPED"); 62 return; 63 } 64 65 if (!CPUInfo.hasFeature(bmiTestCase.getCpuFlag())) { 66 System.out.println("Unsupported hardware, no required CPU flag " + bmiTestCase.getCpuFlag() + " , test SKIPPED"); 67 return; 68 } 69 70 if (!Boolean.valueOf(getVMOption(bmiTestCase.getVMFlag()))) { 71 System.out.println("VM flag " + bmiTestCase.getVMFlag() + " disabled, test SKIPPED"); 72 return; 73 } 74 75 System.out.println(testCase.name()); 76 77 switch (MODE) { 78 case "compiled mode": 79 case "mixed mode": 80 if (TIERED_COMPILATION && TIERED_STOP_AT_LEVEL != CompilerWhiteBoxTest.COMP_LEVEL_MAX) { 81 System.out.println("TieredStopAtLevel value (" + TIERED_STOP_AT_LEVEL + ") is too low, test SKIPPED"); 82 return; 83 } 84 deoptimize(); 85 compileAtLevelAndCheck(CompilerWhiteBoxTest.COMP_LEVEL_MAX); 86 break; 87 case "interpreted mode": // test is not applicable in this mode; 88 System.err.println("Warning: This test is not applicable in mode: " + MODE); 89 break; 90 default: 91 throw new AssertionError("Test bug, unknown VM mode: " + MODE); 92 } 93 } 94 95 protected void compileAtLevelAndCheck(int level) { 96 WHITE_BOX.enqueueMethodForCompilation(method, level); 97 waitBackgroundCompilation(); 98 checkCompilation(method, level); 99 checkEmittedCode(method); 100 } 101 102 protected void checkCompilation(Executable executable, int level) { 103 if (!WHITE_BOX.isMethodCompiled(executable)) { 104 throw new AssertionError("Test bug, expected compilation (level): " + level + ", but not compiled" + WHITE_BOX.isMethodCompilable(executable, level)); 105 } 106 final int compilationLevel = WHITE_BOX.getMethodCompilationLevel(executable); 107 if (compilationLevel != level) { 108 throw new AssertionError("Test bug, expected compilation (level): " + level + ", but level: " + compilationLevel); 109 } 110 } 111 112 protected void checkEmittedCode(Executable executable) { 113 final byte[] nativeCode = NMethod.get(executable, false).insts; 114 if (!((BmiTestCase) testCase).verifyPositive(nativeCode)) { 115 throw new AssertionError(testCase.name() + "CPU instructions expected not found: " + Utils.toHexString(nativeCode)); 116 } else { 117 System.out.println("CPU instructions found, PASSED"); 118 } 119 } 120 121 abstract static class BmiTestCase implements CompilerWhiteBoxTest.TestCase { 122 private final Method method; 123 protected byte[] instrMask; 124 protected byte[] instrPattern; 125 protected boolean isLongOperation; 126 127 public BmiTestCase(Method method) { 128 this.method = method; 129 } 130 131 @Override 132 public String name() { 133 return method.toGenericString(); 134 } 135 136 @Override 137 public Executable getExecutable() { 138 return method; 139 } 140 141 @Override 142 public Callable<Integer> getCallable() { 143 return null; 144 } 145 146 @Override 147 public boolean isOsr() { 148 return false; 149 } 150 151 protected int countCpuInstructions(byte[] nativeCode) { 152 return countCpuInstructions(nativeCode, instrMask, instrPattern); 153 } 154 155 public static int countCpuInstructions(byte[] nativeCode, byte[] instrMask, byte[] instrPattern) { 156 int count = 0; 157 int patternSize = Math.min(instrMask.length, instrPattern.length); 158 boolean found; 159 Asserts.assertGreaterThan(patternSize, 0); 160 for (int i = 0, n = nativeCode.length - patternSize; i < n; i++) { 161 found = true; 162 for (int j = 0; j < patternSize; j++) { 163 if ((nativeCode[i + j] & instrMask[j]) != instrPattern[j]) { 164 found = false; 165 break; 166 } 167 } 168 if (found) { 169 ++count; 170 i += patternSize - 1; 171 } 172 } 173 return count; 174 } 175 176 public boolean verifyPositive(byte[] nativeCode) { 177 final int cnt = countCpuInstructions(nativeCode); 178 if (Platform.isX86()) { 179 return cnt >= (isLongOperation ? 2 : 1); 180 } else { 181 return Platform.isX64() && cnt >= 1; 182 } 183 } 184 185 protected String getCpuFlag() { 186 return "bmi1"; 187 } 188 189 protected String getVMFlag() { 190 return "UseBMI1Instructions"; 191 } 192 } 193 194 abstract static class BmiTestCase_x64 extends BmiTestCase { 195 protected byte[] instrMask_x64; 196 protected byte[] instrPattern_x64; 197 198 protected BmiTestCase_x64(Method method) { 199 super(method); 200 } 201 202 protected int countCpuInstructions(byte[] nativeCode) { 203 int cnt = super.countCpuInstructions(nativeCode); 204 if (Platform.isX64()) { // on x64 platform the instruction we search for can be encoded in 2 different ways 205 cnt += countCpuInstructions(nativeCode, instrMask_x64, instrPattern_x64); 206 } 207 return cnt; 208 } 209 } 210 }