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