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