1 /* 2 * Copyright (c) 2018, 2019, 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 package org.graalvm.compiler.hotspot.test; 27 28 import java.lang.reflect.InvocationTargetException; 29 import java.math.BigInteger; 30 import java.util.Random; 31 32 import org.graalvm.compiler.api.test.Graal; 33 import org.graalvm.compiler.core.test.GraalCompilerTest; 34 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 35 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; 36 import org.graalvm.compiler.runtime.RuntimeProvider; 37 38 import org.junit.Test; 39 40 import jdk.vm.ci.amd64.AMD64; 41 import jdk.vm.ci.code.InstalledCode; 42 import jdk.vm.ci.code.InvalidInstalledCodeException; 43 import jdk.vm.ci.meta.ResolvedJavaMethod; 44 45 /* 46 * Indirectly test intrinsic/call substitutions for (innate) methods: 47 * 48 * BigInteger.implMultiplyToLen 49 * BigInteger.implMulAdd 50 * BigInteger.implMontgomeryMultiply 51 * BigInteger.implMontgomerySquare 52 * BigInteger.implSquareToLen 53 * 54 * via BigInteger.multiply() and .modPow(). Note that the actual substitution 55 * is not tested per se (only execution based on admissible intrinsics). 56 * 57 */ 58 public final class BigIntegerIntrinsicsTest extends GraalCompilerTest { 59 60 static final int N = 100; 61 62 @Test 63 public void testMultiplyToLen() throws ClassNotFoundException { 64 65 // Intrinsic must be available. 66 org.junit.Assume.assumeTrue(config.useMultiplyToLenIntrinsic()); 67 // Test case is (currently) AMD64 only. 68 org.junit.Assume.assumeTrue(getTarget().arch instanceof AMD64); 69 70 Class<?> javaclass = Class.forName("java.math.BigInteger"); 71 72 TestIntrinsic tin = new TestIntrinsic("testMultiplyAux", javaclass, 73 "multiply", BigInteger.class); 74 75 for (int i = 0; i < N; i++) { 76 77 BigInteger big1 = randomBig(i); 78 BigInteger big2 = randomBig(i); 79 80 // Invoke BigInteger BigInteger.multiply(BigInteger) 81 BigInteger res1 = (BigInteger) tin.invokeJava(big1, big2); 82 83 // Invoke BigInteger testMultiplyAux(BigInteger) 84 BigInteger res2 = (BigInteger) tin.invokeTest(big1, big2); 85 86 assertDeepEquals(res1, res2); 87 88 // Invoke BigInteger testMultiplyAux(BigInteger) through code handle. 89 BigInteger res3 = (BigInteger) tin.invokeCode(big1, big2); 90 91 assertDeepEquals(res1, res3); 92 } 93 } 94 95 @Test 96 public void testMulAdd() throws ClassNotFoundException { 97 98 // Intrinsic must be available. 99 org.junit.Assume.assumeTrue(config.useMulAddIntrinsic() || 100 config.useSquareToLenIntrinsic()); 101 // Test case is (currently) AMD64 only. 102 org.junit.Assume.assumeTrue(getTarget().arch instanceof AMD64); 103 104 Class<?> javaclass = Class.forName("java.math.BigInteger"); 105 106 TestIntrinsic tin = new TestIntrinsic("testMultiplyAux", javaclass, 107 "multiply", BigInteger.class); 108 109 for (int i = 0; i < N; i++) { 110 111 BigInteger big1 = randomBig(i); 112 113 // Invoke BigInteger BigInteger.multiply(BigInteger) 114 BigInteger res1 = (BigInteger) tin.invokeJava(big1, big1); 115 116 // Invoke BigInteger testMultiplyAux(BigInteger) 117 BigInteger res2 = (BigInteger) tin.invokeTest(big1, big1); 118 119 assertDeepEquals(res1, res2); 120 121 // Invoke BigInteger testMultiplyAux(BigInteger) through code handle. 122 BigInteger res3 = (BigInteger) tin.invokeCode(big1, big1); 123 124 assertDeepEquals(res1, res3); 125 } 126 } 127 128 @Test 129 public void testMontgomery() throws ClassNotFoundException { 130 131 // Intrinsic must be available. 132 org.junit.Assume.assumeTrue(config.useMontgomeryMultiplyIntrinsic() || 133 config.useMontgomerySquareIntrinsic()); 134 // Test case is (currently) AMD64 only. 135 org.junit.Assume.assumeTrue(getTarget().arch instanceof AMD64); 136 137 Class<?> javaclass = Class.forName("java.math.BigInteger"); 138 139 TestIntrinsic tin = new TestIntrinsic("testMontgomeryAux", javaclass, 140 "modPow", BigInteger.class, BigInteger.class); 141 142 for (int i = 0; i < N; i++) { 143 144 BigInteger big1 = randomBig(i); 145 BigInteger big2 = randomBig(i); 146 147 // Invoke BigInteger BigInteger.modPow(BigExp, BigInteger) 148 BigInteger res1 = (BigInteger) tin.invokeJava(big1, bigTwo, big2); 149 150 // Invoke BigInteger testMontgomeryAux(BigInteger, BigExp, BigInteger) 151 BigInteger res2 = (BigInteger) tin.invokeTest(big1, bigTwo, big2); 152 153 assertDeepEquals(res1, res2); 154 155 // Invoke BigInteger testMontgomeryAux(BigInteger, BigExp, BigInteger) 156 // through code handle. 157 BigInteger res3 = (BigInteger) tin.invokeCode(big1, bigTwo, big2); 158 159 assertDeepEquals(res1, res3); 160 } 161 } 162 163 public static BigInteger testMultiplyAux(BigInteger a, BigInteger b) { 164 return a.multiply(b); 165 } 166 167 public static BigInteger testMontgomeryAux(BigInteger a, BigInteger exp, BigInteger b) { 168 return a.modPow(exp, b); 169 } 170 171 private class TestIntrinsic { 172 173 TestIntrinsic(String testmname, Class<?> javaclass, String javamname, Class<?>... params) { 174 javamethod = getResolvedJavaMethod(javaclass, javamname, params); 175 testmethod = getResolvedJavaMethod(testmname); 176 177 assert javamethod != null; 178 assert testmethod != null; 179 180 // Force the test method to be compiled. 181 testcode = getCode(testmethod); 182 183 assert testcode != null; 184 assert testcode.isValid(); 185 } 186 187 Object invokeJava(BigInteger big, Object... args) { 188 return invokeSafe(javamethod, big, args); 189 } 190 191 Object invokeTest(Object... args) { 192 return invokeSafe(testmethod, null, args); 193 } 194 195 Object invokeCode(Object... args) { 196 try { 197 return testcode.executeVarargs(args); 198 } catch (InvalidInstalledCodeException e) { 199 // Ensure the installed code is valid, possibly recompiled. 200 testcode = getCode(testmethod); 201 202 assert testcode != null; 203 assert testcode.isValid(); 204 205 return invokeCode(args); 206 } 207 } 208 209 private Object invokeSafe(ResolvedJavaMethod method, Object receiver, Object... args) { 210 try { 211 return invoke(method, receiver, args); 212 } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException | InstantiationException e) { 213 throw new RuntimeException(e); 214 } 215 } 216 217 // Private data section: 218 private ResolvedJavaMethod javamethod; 219 private ResolvedJavaMethod testmethod; 220 private InstalledCode testcode; 221 } 222 223 private static GraalHotSpotVMConfig config = ((HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class)).getVMConfig(); 224 225 private static BigInteger bigTwo = BigInteger.valueOf(2); 226 private static Random rnd = new Random(17); 227 228 private static BigInteger randomBig(int i) { 229 return new BigInteger(rnd.nextInt(4096) + i2sz(i), rnd); 230 } 231 232 private static int i2sz(int i) { 233 return i * 3 + 1; 234 } 235 }