JDK 9 RFR of JDK-8035279: Clean up internal deprecations in BigInteger

Paul Sandoz paul.sandoz at oracle.com
Wed Feb 26 13:38:18 UTC 2014

On Feb 25, 2014, at 9:38 PM, Brian Burkhalter <brian.burkhalter at oracle.com> wrote:

> On Feb 20, 2014, at 1:42 AM, Paul Sandoz wrote:
>> Not sure the static powerCache field, in the original code, needs to be volatile either:
>> 1137     private static volatile BigInteger[][] powerCache;
> Is there consensus on whether "volatile" is necessary here?

Looking back at the discussions i believe it was made volatile to ensure threads don't observe a partially updated and published cache lines.

Since we are already using Unsafe for deserialization I think it might be possible to do the following instead (warning: not tested!):

     * The cache of powers of each radix.  This allows us to not have to
     * recalculate powers of radix^(2^n) more than once.  This speeds
     * Schoenhage recursive base conversion significantly.
    private static final BigInteger[][] powerCache;


    private static BigInteger getRadixConversionCache(int radix, int exponent) {
        // Relaxed read of cache line from power cache
        BigInteger[] cacheLine = powerCache[radix];
        if (exponent < cacheLine.length) {
            return cacheLine[exponent];

        // Copy and expand the cache line up to and including the exponent
        int oldLength = cacheLine.length;
        cacheLine = Arrays.copyOf(cacheLine, exponent + 1);
        for (int i = oldLength; i <= exponent; i++) {
            cacheLine[i] = cacheLine[i - 1].pow(2);

        // Lazy write of new cache line to power cache
        // Ensure all writes to the new cache line are ordered before
        // it's publication in the power cache
        UnsafeHolder.lazySetCacheLine(powerCache, radix, cacheLine);

        return cacheLine[exponent];

    private static class UnsafeHolder {
        private static final sun.misc.Unsafe unsafe;
        private static final long signumOffset;
        private static final long magOffset;
        private static final int biaOffset;
        private static final int biaShift;

        static {
            try {
                unsafe = sun.misc.Unsafe.getUnsafe();
                signumOffset = unsafe.objectFieldOffset
                magOffset = unsafe.objectFieldOffset

                biaOffset = unsafe.arrayBaseOffset(BigInteger[][].class);
                int scale = unsafe.arrayIndexScale(BigInteger[][].class);
                if ((scale & (scale - 1)) != 0)
                    throw new Error("data type scale not a power of two");
                biaShift = 31 - Integer.numberOfLeadingZeros(scale);

            } catch (Exception ex) {
                throw new ExceptionInInitializerError(ex);

        static void putSign(BigInteger bi, int sign) {
            unsafe.putIntVolatile(bi, signumOffset, sign);

        static void putMag(BigInteger bi, int[] magnitude) {
            unsafe.putObjectVolatile(bi, magOffset, magnitude);

        static void lazySetCacheLine(BigInteger[][] cache, int radix,
                                        BigInteger[] cacheLine) {
            unsafe.putOrderedObject(cache, biaOffset + ((long) radix << biaShift),


More information about the core-libs-dev mailing list