JDK-8152910 : Get performance improvement with Stable annotation
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.math
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2016-03-29
  • Updated: 2018-10-17
  • Resolved: 2018-10-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 12
12 b16Fixed
Related Reports
Relates :  
Description
Peter Levart posted in OpenJDK:
------------------------------------------
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


Peter Levart evaluation in OpenJDK:
----------------------------------------------
 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.
Comments
Maybe worthy further evaluation to use Stable annotation on java.math.BigInteger, java.lang.Byte, Character, Short, Integer & Long, etc.
30-03-2016

According to Peter Levart's evaluation, the Stable annotation can improve the performance of BigInteger.valueOf() by around 15%. Maybe worthy further evaluation to use Stable annotation on java.lang.Byte, Character, Short, Integer & Long, too. This is a kind of core lib improvement. If the java crypto performance get improvement with Stable annotation, maybe we can push for an update.
29-03-2016