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
(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.
More information about the core-libs-dev
mailing list