Ok, here's a test...

with just the following change:


diff -r 9ea9fb3c0c88 src/java.base/share/classes/java/math/BigInteger.java
--- a/src/java.base/share/classes/java/math/BigInteger.java Wed Mar 23 18:24:35 2016 +0100 +++ b/src/java.base/share/classes/java/math/BigInteger.java Wed Mar 23 19:55:01 2016 +0100
@@ -41,6 +41,7 @@
 import jdk.internal.math.DoubleConsts;
 import jdk.internal.math.FloatConsts;
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.vm.annotation.Stable;

 /**
  * Immutable arbitrary-precision integers.  All operations behave as if
@@ -1213,8 +1214,10 @@
      * Initialize static constant array when class is loaded.
      */
     private static final int MAX_CONSTANT = 16;
-    private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
-    private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];
+    @Stable
+ private static final BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
+    @Stable
+ private static final BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];

     /**
      * The cache of powers of each radix.  This allows us to not have to



The results of simple benchmark:

/*

Original:

Benchmark                  Mode  Cnt  Score   Error  Units
BigIntegerBench.ONE        avgt   10  2.396 ± 0.232  ns/op
BigIntegerBench.valueOf_1  avgt   10  2.846 ± 0.233  ns/op
BigIntegerBench.valueOf_2  avgt   10  2.808 ± 0.054  ns/op

Patched:

Benchmark                  Mode  Cnt  Score   Error  Units
BigIntegerBench.ONE        avgt   10  2.381 ± 0.126  ns/op
BigIntegerBench.valueOf_1  avgt   10  2.347 ± 0.089  ns/op
BigIntegerBench.valueOf_2  avgt   10  2.323 ± 0.022  ns/op

*/
package jdk.test;

import org.openjdk.jmh.annotations.*;

import java.math.BigInteger;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@Fork(1)
@Warmup(iterations = 5)
@Measurement(iterations = 10)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class BigIntegerBench {

    @Benchmark
    public BigInteger ONE() {
        return BigInteger.ONE;
    }

    @Benchmark
    public BigInteger valueOf_1() {
        return BigInteger.valueOf(1);
    }

    @Benchmark
    public BigInteger valueOf_2() {
        return BigInteger.valueOf(2);
    }
}


So, no need to change the API and all uses of valueOf(-MAX_CONSTANT <= i <= MAX_CONSTANT) for constant 'i' will be faster a bit.

Regards, Peter


On 03/23/2016 07:01 PM, Peter Levart wrote:
Hi Xuelei,

On 03/23/2016 04:26 AM, Xuelei Fan wrote:
Hi,

Please review the update for the supporting of BigInteger.TWO:

http://cr.openjdk.java.net/~xuelei/8152237/webrev/

BigInteger.valueOf(2) is a common BigInteger value used in binary and cryptography operation calculation. The BigInteger.TWO is not exported, and hence BigInteger.valueOf(2) is used instead in applications and JDK components. The export of static BigInteger.TWO can improve performance and simplify existing code.

Thanks,
Xuelei

I think (haven't tried, just speculate) you could achieve the same performance by:

- adding final qualifier to static BigInteger.[posConst|negConst] fields
- annotating those fields with @jdk.internal.vm.annotation.Stable annotation

This way BigInteger.valueOf(-MAX_CONSTANT <= i <= MAX_CONSTANT) when called with a constant argument should fold into a constant when compiled by JIT.

The same optimization could be performed for valueOf methods of java.lang.Byte, Character, Short, Integer & Long.

@Stable annotation was a package-private annotation in java.lang.invoke, reserved for method handles infrastructure, but has since been made public and moved to a concealed package of java.base. There is already a precedent for its use outside in java.lang.invoke: in java.lang.String. For example:

static final String s = ".....";

s.charAt(0); // is folded into a constant by JIT



Regards, Peter


Reply via email to