1 /* 2 * Copyright (c) 2012, 2018, 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 package org.graalvm.compiler.replacements.test; 26 27 import java.util.HashMap; 28 29 import org.graalvm.compiler.api.replacements.MethodSubstitution; 30 import org.graalvm.compiler.nodes.IfNode; 31 import org.graalvm.compiler.nodes.StructuredGraph; 32 import org.graalvm.compiler.nodes.calc.AbsNode; 33 import org.graalvm.compiler.nodes.calc.ReinterpretNode; 34 import org.graalvm.compiler.replacements.nodes.BitCountNode; 35 import org.graalvm.compiler.replacements.nodes.BitScanForwardNode; 36 import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; 37 import org.graalvm.compiler.replacements.nodes.ReverseBytesNode; 38 import org.junit.Test; 39 40 import jdk.vm.ci.code.InstalledCode; 41 import jdk.vm.ci.meta.ResolvedJavaMethod; 42 43 /** 44 * Tests the VM independent {@link MethodSubstitution}s. 45 */ 46 public class StandardMethodSubstitutionsTest extends MethodSubstitutionTest { 47 48 @Test 49 public void testMathSubstitutions() { 50 assertInGraph(assertNotInGraph(testGraph("mathAbs"), IfNode.class), AbsNode.class); // Java 51 double value = 34567.891D; 52 testGraph("mathCos"); 53 testGraph("mathLog"); 54 testGraph("mathLog10"); 55 testGraph("mathSin"); 56 testGraph("mathSqrt"); 57 testGraph("mathTan"); 58 testGraph("mathAll"); 59 60 test("mathCos", value); 61 test("mathLog", value); 62 test("mathLog10", value); 63 test("mathSin", value); 64 test("mathSqrt", value); 65 test("mathTan", value); 66 test("mathAll", value); 67 } 68 69 @Test 70 public void testMathPow() { 71 double a = 34567.891D; 72 double b = 4.6D; 73 test("mathPow", a, b); 74 75 // Test the values directly handled by the substitution 76 77 // If the second argument is positive or negative zero, then the result is 1.0. 78 test("mathPow", a, 0.0D); 79 test("mathPow", a, -0.0D); 80 // If the second argument is 1.0, then the result is the same as the first argument. 81 test("mathPow", a, 1.0D); 82 // If the second argument is NaN, then the result is NaN. 83 test("mathPow", a, Double.NaN); 84 // If the first argument is NaN and the second argument is nonzero, then the result is NaN. 85 test("mathPow", Double.NaN, b); 86 test("mathPow", Double.NaN, 0.0D); 87 // x**-1 = 1/x 88 test("mathPow", a, -1.0D); 89 // x**2 = x*x 90 test("mathPow", a, 2.0D); 91 // x**0.5 = sqrt(x) 92 test("mathPow", a, 0.5D); 93 } 94 95 public static double mathPow(double a, double b) { 96 return mathPow0(a, b); 97 } 98 99 public static double mathPow0(double a, double b) { 100 return Math.pow(a, b); 101 } 102 103 public static double mathAbs(double value) { 104 return Math.abs(value); 105 } 106 107 public static double mathSqrt(double value) { 108 return Math.sqrt(value); 109 } 110 111 public static double mathLog(double value) { 112 return Math.log(value); 113 } 114 115 public static double mathLog10(double value) { 116 return Math.log10(value); 117 } 118 119 public static double mathSin(double value) { 120 return Math.sin(value); 121 } 122 123 public static double mathCos(double value) { 124 return Math.cos(value); 125 } 126 127 public static double mathTan(double value) { 128 return Math.tan(value); 129 } 130 131 public static double mathAll(double value) { 132 return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value); 133 } 134 135 public void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, boolean optional, Object... args) { 136 ResolvedJavaMethod realJavaMethod = getResolvedJavaMethod(holder, methodName); 137 ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod(testMethodName); 138 StructuredGraph graph = testGraph(testMethodName); 139 140 // Check to see if the resulting graph contains the expected node 141 StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1, false, null, graph.getOptions()); 142 if (replacement == null && !optional) { 143 assertInGraph(graph, intrinsicClass); 144 } 145 146 for (Object l : args) { 147 // Force compilation 148 InstalledCode code = getCode(testJavaMethod); 149 assert optional || code != null; 150 // Verify that the original method and the substitution produce the same value 151 Object expected = invokeSafe(realJavaMethod, null, l); 152 assertDeepEquals(expected, invokeSafe(testJavaMethod, null, l)); 153 // Verify that the generated code and the original produce the same value 154 assertDeepEquals(expected, executeVarargsSafe(code, l)); 155 } 156 } 157 158 @Test 159 public void testCharSubstitutions() { 160 Object[] args = new Character[]{Character.MIN_VALUE, (char) -1, (char) 0, (char) 1, Character.MAX_VALUE}; 161 162 testSubstitution("charReverseBytes", ReverseBytesNode.class, Character.class, "reverseBytes", false, args); 163 } 164 165 public static char charReverseBytes(char value) { 166 return Character.reverseBytes(value); 167 } 168 169 @Test 170 public void testCharSubstitutionsNarrowing() { 171 Object[] args = new Integer[]{(int) Character.MIN_VALUE, -1, 0, 1, (int) Character.MAX_VALUE}; 172 173 for (Object arg : args) { 174 test("charReverseBytesNarrowing", arg); 175 } 176 } 177 178 public static char charReverseBytesNarrowing(int value) { 179 return Character.reverseBytes((char) value); 180 } 181 182 @Test 183 public void testShortSubstitutions() { 184 Object[] args = new Short[]{Short.MIN_VALUE, -1, 0, 1, Short.MAX_VALUE}; 185 186 testSubstitution("shortReverseBytes", ReverseBytesNode.class, Short.class, "reverseBytes", false, args); 187 } 188 189 public static short shortReverseBytes(short value) { 190 return Short.reverseBytes(value); 191 } 192 193 @Test 194 public void testShortSubstitutionsNarrowing() { 195 Object[] args = new Integer[]{(int) Short.MIN_VALUE, -1, 0, 1, (int) Short.MAX_VALUE}; 196 197 for (Object arg : args) { 198 test("shortReverseBytesNarrowing", arg); 199 } 200 } 201 202 public static short shortReverseBytesNarrowing(int value) { 203 return Short.reverseBytes((short) value); 204 } 205 206 @Test 207 public void testIntegerSubstitutions() { 208 Object[] args = new Object[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE}; 209 210 testSubstitution("integerReverseBytes", ReverseBytesNode.class, Integer.class, "reverseBytes", false, args); 211 testSubstitution("integerNumberOfLeadingZeros", BitScanReverseNode.class, Integer.class, "numberOfLeadingZeros", true, args); 212 testSubstitution("integerNumberOfTrailingZeros", BitScanForwardNode.class, Integer.class, "numberOfTrailingZeros", false, args); 213 testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args); 214 } 215 216 public static int integerReverseBytes(int value) { 217 return Integer.reverseBytes(value); 218 } 219 220 public static int integerNumberOfLeadingZeros(int value) { 221 return Integer.numberOfLeadingZeros(value); 222 } 223 224 public static int integerNumberOfTrailingZeros(int value) { 225 return Integer.numberOfTrailingZeros(value); 226 } 227 228 public static int integerBitCount(int value) { 229 return Integer.bitCount(value); 230 } 231 232 @Test 233 public void testLongSubstitutions() { 234 Object[] args = new Object[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE}; 235 236 testSubstitution("longReverseBytes", ReverseBytesNode.class, Long.class, "reverseBytes", false, args); 237 testSubstitution("longNumberOfLeadingZeros", BitScanReverseNode.class, Long.class, "numberOfLeadingZeros", true, args); 238 testSubstitution("longNumberOfTrailingZeros", BitScanForwardNode.class, Long.class, "numberOfTrailingZeros", false, args); 239 testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args); 240 } 241 242 public static long longReverseBytes(long value) { 243 return Long.reverseBytes(value); 244 } 245 246 public static int longNumberOfLeadingZeros(long value) { 247 return Long.numberOfLeadingZeros(value); 248 } 249 250 public static int longNumberOfTrailingZeros(long value) { 251 return Long.numberOfTrailingZeros(value); 252 } 253 254 public static int longBitCount(long value) { 255 return Long.bitCount(value); 256 } 257 258 @Test 259 public void testFloatSubstitutions() { 260 assertInGraph(testGraph("floatToIntBits"), ReinterpretNode.class); // Java 261 testGraph("intBitsToFloat"); 262 } 263 264 public static int floatToIntBits(float value) { 265 return Float.floatToIntBits(value); 266 } 267 268 public static float intBitsToFloat(int value) { 269 return Float.intBitsToFloat(value); 270 } 271 272 @Test 273 public void testDoubleSubstitutions() { 274 assertInGraph(testGraph("doubleToLongBits"), ReinterpretNode.class); // Java 275 testGraph("longBitsToDouble"); 276 } 277 278 public static long doubleToLongBits(double value) { 279 return Double.doubleToLongBits(value); 280 } 281 282 public static double longBitsToDouble(long value) { 283 return Double.longBitsToDouble(value); 284 } 285 286 public static boolean isInstance(Class<?> clazz, Object object) { 287 return clazz.isInstance(object); 288 } 289 290 public static boolean isInstance2(boolean cond, Object object) { 291 Class<?> clazz; 292 if (cond) { 293 clazz = String.class; 294 } else { 295 clazz = java.util.HashMap.class; 296 } 297 return clazz.isInstance(object); 298 } 299 300 public static boolean isAssignableFrom(Class<?> clazz, Class<?> other) { 301 return clazz.isAssignableFrom(other); 302 } 303 304 @Test 305 public void testClassSubstitutions() { 306 testGraph("isInstance"); 307 testGraph("isInstance2"); 308 testGraph("isAssignableFrom"); 309 for (Class<?> c : new Class<?>[]{getClass(), Cloneable.class, int[].class, String[][].class}) { 310 for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) { 311 test("isInstance", c, o); 312 test("isAssignableFrom", c, o.getClass()); 313 } 314 } 315 316 test("isInstance2", true, null); 317 test("isInstance2", false, null); 318 test("isInstance2", true, "string"); 319 test("isInstance2", false, "string"); 320 test("isInstance2", true, new HashMap<>()); 321 test("isInstance2", false, new HashMap<>()); 322 } 323 }