On Feb 25, 2014, at 9:38 PM, Brian Burkhalter <brian.burkhal...@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 (BigInteger.class.getDeclaredField("signum")); magOffset = unsafe.objectFieldOffset (BigInteger.class.getDeclaredField("mag")); 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), cacheLine); } } Paul.