|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package java.nio; |
|
|
|
import java.security.AccessController; |
|
import java.util.concurrent.atomic.AtomicLong; |
|
import java.util.concurrent.atomic.LongAdder; |
|
|
|
import sun.misc.JavaLangRefAccess; |
|
import sun.misc.SharedSecrets; |
|
import sun.misc.Unsafe; |
|
import sun.misc.VM; |
|
|
|
/** |
|
* Access to bits, native and otherwise. |
|
*/ |
|
|
|
class Bits { |
|
|
|
private Bits() { } |
|
|
|
|
|
// -- Swapping -- |
|
|
|
static short swap(short x) { |
|
return Short.reverseBytes(x); |
|
} |
|
|
|
static char swap(char x) { |
|
return Character.reverseBytes(x); |
|
} |
|
|
|
static int swap(int x) { |
|
return Integer.reverseBytes(x); |
|
} |
|
|
|
static long swap(long x) { |
|
return Long.reverseBytes(x); |
|
} |
|
|
|
|
|
// -- get/put char -- |
|
|
|
static private char makeChar(byte b1, byte b0) { |
|
return (char)((b1 << 8) | (b0 & 0xff)); |
|
} |
|
|
|
static char getCharL(ByteBuffer bb, int bi) { |
|
return makeChar(bb._get(bi + 1), |
|
bb._get(bi )); |
|
} |
|
|
|
static char getCharL(long a) { |
|
return makeChar(_get(a + 1), |
|
_get(a )); |
|
} |
|
|
|
static char getCharB(ByteBuffer bb, int bi) { |
|
return makeChar(bb._get(bi ), |
|
bb._get(bi + 1)); |
|
} |
|
|
|
static char getCharB(long a) { |
|
return makeChar(_get(a ), |
|
_get(a + 1)); |
|
} |
|
|
|
static char getChar(ByteBuffer bb, int bi, boolean bigEndian) { |
|
return bigEndian ? getCharB(bb, bi) : getCharL(bb, bi); |
|
} |
|
|
|
static char getChar(long a, boolean bigEndian) { |
|
return bigEndian ? getCharB(a) : getCharL(a); |
|
} |
|
|
|
private static byte char1(char x) { return (byte)(x >> 8); } |
|
private static byte char0(char x) { return (byte)(x ); } |
|
|
|
static void putCharL(ByteBuffer bb, int bi, char x) { |
|
bb._put(bi , char0(x)); |
|
bb._put(bi + 1, char1(x)); |
|
} |
|
|
|
static void putCharL(long a, char x) { |
|
_put(a , char0(x)); |
|
_put(a + 1, char1(x)); |
|
} |
|
|
|
static void putCharB(ByteBuffer bb, int bi, char x) { |
|
bb._put(bi , char1(x)); |
|
bb._put(bi + 1, char0(x)); |
|
} |
|
|
|
static void putCharB(long a, char x) { |
|
_put(a , char1(x)); |
|
_put(a + 1, char0(x)); |
|
} |
|
|
|
static void putChar(ByteBuffer bb, int bi, char x, boolean bigEndian) { |
|
if (bigEndian) |
|
putCharB(bb, bi, x); |
|
else |
|
putCharL(bb, bi, x); |
|
} |
|
|
|
static void putChar(long a, char x, boolean bigEndian) { |
|
if (bigEndian) |
|
putCharB(a, x); |
|
else |
|
putCharL(a, x); |
|
} |
|
|
|
|
|
// -- get/put short -- |
|
|
|
static private short makeShort(byte b1, byte b0) { |
|
return (short)((b1 << 8) | (b0 & 0xff)); |
|
} |
|
|
|
static short getShortL(ByteBuffer bb, int bi) { |
|
return makeShort(bb._get(bi + 1), |
|
bb._get(bi )); |
|
} |
|
|
|
static short getShortL(long a) { |
|
return makeShort(_get(a + 1), |
|
_get(a )); |
|
} |
|
|
|
static short getShortB(ByteBuffer bb, int bi) { |
|
return makeShort(bb._get(bi ), |
|
bb._get(bi + 1)); |
|
} |
|
|
|
static short getShortB(long a) { |
|
return makeShort(_get(a ), |
|
_get(a + 1)); |
|
} |
|
|
|
static short getShort(ByteBuffer bb, int bi, boolean bigEndian) { |
|
return bigEndian ? getShortB(bb, bi) : getShortL(bb, bi); |
|
} |
|
|
|
static short getShort(long a, boolean bigEndian) { |
|
return bigEndian ? getShortB(a) : getShortL(a); |
|
} |
|
|
|
private static byte short1(short x) { return (byte)(x >> 8); } |
|
private static byte short0(short x) { return (byte)(x ); } |
|
|
|
static void putShortL(ByteBuffer bb, int bi, short x) { |
|
bb._put(bi , short0(x)); |
|
bb._put(bi + 1, short1(x)); |
|
} |
|
|
|
static void putShortL(long a, short x) { |
|
_put(a , short0(x)); |
|
_put(a + 1, short1(x)); |
|
} |
|
|
|
static void putShortB(ByteBuffer bb, int bi, short x) { |
|
bb._put(bi , short1(x)); |
|
bb._put(bi + 1, short0(x)); |
|
} |
|
|
|
static void putShortB(long a, short x) { |
|
_put(a , short1(x)); |
|
_put(a + 1, short0(x)); |
|
} |
|
|
|
static void putShort(ByteBuffer bb, int bi, short x, boolean bigEndian) { |
|
if (bigEndian) |
|
putShortB(bb, bi, x); |
|
else |
|
putShortL(bb, bi, x); |
|
} |
|
|
|
static void putShort(long a, short x, boolean bigEndian) { |
|
if (bigEndian) |
|
putShortB(a, x); |
|
else |
|
putShortL(a, x); |
|
} |
|
|
|
|
|
// -- get/put int -- |
|
|
|
static private int makeInt(byte b3, byte b2, byte b1, byte b0) { |
|
return (((b3 ) << 24) | |
|
((b2 & 0xff) << 16) | |
|
((b1 & 0xff) << 8) | |
|
((b0 & 0xff) )); |
|
} |
|
|
|
static int getIntL(ByteBuffer bb, int bi) { |
|
return makeInt(bb._get(bi + 3), |
|
bb._get(bi + 2), |
|
bb._get(bi + 1), |
|
bb._get(bi )); |
|
} |
|
|
|
static int getIntL(long a) { |
|
return makeInt(_get(a + 3), |
|
_get(a + 2), |
|
_get(a + 1), |
|
_get(a )); |
|
} |
|
|
|
static int getIntB(ByteBuffer bb, int bi) { |
|
return makeInt(bb._get(bi ), |
|
bb._get(bi + 1), |
|
bb._get(bi + 2), |
|
bb._get(bi + 3)); |
|
} |
|
|
|
static int getIntB(long a) { |
|
return makeInt(_get(a ), |
|
_get(a + 1), |
|
_get(a + 2), |
|
_get(a + 3)); |
|
} |
|
|
|
static int getInt(ByteBuffer bb, int bi, boolean bigEndian) { |
|
return bigEndian ? getIntB(bb, bi) : getIntL(bb, bi) ; |
|
} |
|
|
|
static int getInt(long a, boolean bigEndian) { |
|
return bigEndian ? getIntB(a) : getIntL(a) ; |
|
} |
|
|
|
private static byte int3(int x) { return (byte)(x >> 24); } |
|
private static byte int2(int x) { return (byte)(x >> 16); } |
|
private static byte int1(int x) { return (byte)(x >> 8); } |
|
private static byte int0(int x) { return (byte)(x ); } |
|
|
|
static void putIntL(ByteBuffer bb, int bi, int x) { |
|
bb._put(bi + 3, int3(x)); |
|
bb._put(bi + 2, int2(x)); |
|
bb._put(bi + 1, int1(x)); |
|
bb._put(bi , int0(x)); |
|
} |
|
|
|
static void putIntL(long a, int x) { |
|
_put(a + 3, int3(x)); |
|
_put(a + 2, int2(x)); |
|
_put(a + 1, int1(x)); |
|
_put(a , int0(x)); |
|
} |
|
|
|
static void putIntB(ByteBuffer bb, int bi, int x) { |
|
bb._put(bi , int3(x)); |
|
bb._put(bi + 1, int2(x)); |
|
bb._put(bi + 2, int1(x)); |
|
bb._put(bi + 3, int0(x)); |
|
} |
|
|
|
static void putIntB(long a, int x) { |
|
_put(a , int3(x)); |
|
_put(a + 1, int2(x)); |
|
_put(a + 2, int1(x)); |
|
_put(a + 3, int0(x)); |
|
} |
|
|
|
static void putInt(ByteBuffer bb, int bi, int x, boolean bigEndian) { |
|
if (bigEndian) |
|
putIntB(bb, bi, x); |
|
else |
|
putIntL(bb, bi, x); |
|
} |
|
|
|
static void putInt(long a, int x, boolean bigEndian) { |
|
if (bigEndian) |
|
putIntB(a, x); |
|
else |
|
putIntL(a, x); |
|
} |
|
|
|
|
|
// -- get/put long -- |
|
|
|
static private long makeLong(byte b7, byte b6, byte b5, byte b4, |
|
byte b3, byte b2, byte b1, byte b0) |
|
{ |
|
return ((((long)b7 ) << 56) | |
|
(((long)b6 & 0xff) << 48) | |
|
(((long)b5 & 0xff) << 40) | |
|
(((long)b4 & 0xff) << 32) | |
|
(((long)b3 & 0xff) << 24) | |
|
(((long)b2 & 0xff) << 16) | |
|
(((long)b1 & 0xff) << 8) | |
|
(((long)b0 & 0xff) )); |
|
} |
|
|
|
static long getLongL(ByteBuffer bb, int bi) { |
|
return makeLong(bb._get(bi + 7), |
|
bb._get(bi + 6), |
|
bb._get(bi + 5), |
|
bb._get(bi + 4), |
|
bb._get(bi + 3), |
|
bb._get(bi + 2), |
|
bb._get(bi + 1), |
|
bb._get(bi )); |
|
} |
|
|
|
static long getLongL(long a) { |
|
return makeLong(_get(a + 7), |
|
_get(a + 6), |
|
_get(a + 5), |
|
_get(a + 4), |
|
_get(a + 3), |
|
_get(a + 2), |
|
_get(a + 1), |
|
_get(a )); |
|
} |
|
|
|
static long getLongB(ByteBuffer bb, int bi) { |
|
return makeLong(bb._get(bi ), |
|
bb._get(bi + 1), |
|
bb._get(bi + 2), |
|
bb._get(bi + 3), |
|
bb._get(bi + 4), |
|
bb._get(bi + 5), |
|
bb._get(bi + 6), |
|
bb._get(bi + 7)); |
|
} |
|
|
|
static long getLongB(long a) { |
|
return makeLong(_get(a ), |
|
_get(a + 1), |
|
_get(a + 2), |
|
_get(a + 3), |
|
_get(a + 4), |
|
_get(a + 5), |
|
_get(a + 6), |
|
_get(a + 7)); |
|
} |
|
|
|
static long getLong(ByteBuffer bb, int bi, boolean bigEndian) { |
|
return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi); |
|
} |
|
|
|
static long getLong(long a, boolean bigEndian) { |
|
return bigEndian ? getLongB(a) : getLongL(a); |
|
} |
|
|
|
private static byte long7(long x) { return (byte)(x >> 56); } |
|
private static byte long6(long x) { return (byte)(x >> 48); } |
|
private static byte long5(long x) { return (byte)(x >> 40); } |
|
private static byte long4(long x) { return (byte)(x >> 32); } |
|
private static byte long3(long x) { return (byte)(x >> 24); } |
|
private static byte long2(long x) { return (byte)(x >> 16); } |
|
private static byte long1(long x) { return (byte)(x >> 8); } |
|
private static byte long0(long x) { return (byte)(x ); } |
|
|
|
static void putLongL(ByteBuffer bb, int bi, long x) { |
|
bb._put(bi + 7, long7(x)); |
|
bb._put(bi + 6, long6(x)); |
|
bb._put(bi + 5, long5(x)); |
|
bb._put(bi + 4, long4(x)); |
|
bb._put(bi + 3, long3(x)); |
|
bb._put(bi + 2, long2(x)); |
|
bb._put(bi + 1, long1(x)); |
|
bb._put(bi , long0(x)); |
|
} |
|
|
|
static void putLongL(long a, long x) { |
|
_put(a + 7, long7(x)); |
|
_put(a + 6, long6(x)); |
|
_put(a + 5, long5(x)); |
|
_put(a + 4, long4(x)); |
|
_put(a + 3, long3(x)); |
|
_put(a + 2, long2(x)); |
|
_put(a + 1, long1(x)); |
|
_put(a , long0(x)); |
|
} |
|
|
|
static void putLongB(ByteBuffer bb, int bi, long x) { |
|
bb._put(bi , long7(x)); |
|
bb._put(bi + 1, long6(x)); |
|
bb._put(bi + 2, long5(x)); |
|
bb._put(bi + 3, long4(x)); |
|
bb._put(bi + 4, long3(x)); |
|
bb._put(bi + 5, long2(x)); |
|
bb._put(bi + 6, long1(x)); |
|
bb._put(bi + 7, long0(x)); |
|
} |
|
|
|
static void putLongB(long a, long x) { |
|
_put(a , long7(x)); |
|
_put(a + 1, long6(x)); |
|
_put(a + 2, long5(x)); |
|
_put(a + 3, long4(x)); |
|
_put(a + 4, long3(x)); |
|
_put(a + 5, long2(x)); |
|
_put(a + 6, long1(x)); |
|
_put(a + 7, long0(x)); |
|
} |
|
|
|
static void putLong(ByteBuffer bb, int bi, long x, boolean bigEndian) { |
|
if (bigEndian) |
|
putLongB(bb, bi, x); |
|
else |
|
putLongL(bb, bi, x); |
|
} |
|
|
|
static void putLong(long a, long x, boolean bigEndian) { |
|
if (bigEndian) |
|
putLongB(a, x); |
|
else |
|
putLongL(a, x); |
|
} |
|
|
|
|
|
// -- get/put float -- |
|
|
|
static float getFloatL(ByteBuffer bb, int bi) { |
|
return Float.intBitsToFloat(getIntL(bb, bi)); |
|
} |
|
|
|
static float getFloatL(long a) { |
|
return Float.intBitsToFloat(getIntL(a)); |
|
} |
|
|
|
static float getFloatB(ByteBuffer bb, int bi) { |
|
return Float.intBitsToFloat(getIntB(bb, bi)); |
|
} |
|
|
|
static float getFloatB(long a) { |
|
return Float.intBitsToFloat(getIntB(a)); |
|
} |
|
|
|
static float getFloat(ByteBuffer bb, int bi, boolean bigEndian) { |
|
return bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi); |
|
} |
|
|
|
static float getFloat(long a, boolean bigEndian) { |
|
return bigEndian ? getFloatB(a) : getFloatL(a); |
|
} |
|
|
|
static void putFloatL(ByteBuffer bb, int bi, float x) { |
|
putIntL(bb, bi, Float.floatToRawIntBits(x)); |
|
} |
|
|
|
static void putFloatL(long a, float x) { |
|
putIntL(a, Float.floatToRawIntBits(x)); |
|
} |
|
|
|
static void putFloatB(ByteBuffer bb, int bi, float x) { |
|
putIntB(bb, bi, Float.floatToRawIntBits(x)); |
|
} |
|
|
|
static void putFloatB(long a, float x) { |
|
putIntB(a, Float.floatToRawIntBits(x)); |
|
} |
|
|
|
static void putFloat(ByteBuffer bb, int bi, float x, boolean bigEndian) { |
|
if (bigEndian) |
|
putFloatB(bb, bi, x); |
|
else |
|
putFloatL(bb, bi, x); |
|
} |
|
|
|
static void putFloat(long a, float x, boolean bigEndian) { |
|
if (bigEndian) |
|
putFloatB(a, x); |
|
else |
|
putFloatL(a, x); |
|
} |
|
|
|
|
|
// -- get/put double -- |
|
|
|
static double getDoubleL(ByteBuffer bb, int bi) { |
|
return Double.longBitsToDouble(getLongL(bb, bi)); |
|
} |
|
|
|
static double getDoubleL(long a) { |
|
return Double.longBitsToDouble(getLongL(a)); |
|
} |
|
|
|
static double getDoubleB(ByteBuffer bb, int bi) { |
|
return Double.longBitsToDouble(getLongB(bb, bi)); |
|
} |
|
|
|
static double getDoubleB(long a) { |
|
return Double.longBitsToDouble(getLongB(a)); |
|
} |
|
|
|
static double getDouble(ByteBuffer bb, int bi, boolean bigEndian) { |
|
return bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi); |
|
} |
|
|
|
static double getDouble(long a, boolean bigEndian) { |
|
return bigEndian ? getDoubleB(a) : getDoubleL(a); |
|
} |
|
|
|
static void putDoubleL(ByteBuffer bb, int bi, double x) { |
|
putLongL(bb, bi, Double.doubleToRawLongBits(x)); |
|
} |
|
|
|
static void putDoubleL(long a, double x) { |
|
putLongL(a, Double.doubleToRawLongBits(x)); |
|
} |
|
|
|
static void putDoubleB(ByteBuffer bb, int bi, double x) { |
|
putLongB(bb, bi, Double.doubleToRawLongBits(x)); |
|
} |
|
|
|
static void putDoubleB(long a, double x) { |
|
putLongB(a, Double.doubleToRawLongBits(x)); |
|
} |
|
|
|
static void putDouble(ByteBuffer bb, int bi, double x, boolean bigEndian) { |
|
if (bigEndian) |
|
putDoubleB(bb, bi, x); |
|
else |
|
putDoubleL(bb, bi, x); |
|
} |
|
|
|
static void putDouble(long a, double x, boolean bigEndian) { |
|
if (bigEndian) |
|
putDoubleB(a, x); |
|
else |
|
putDoubleL(a, x); |
|
} |
|
|
|
|
|
// -- Unsafe access -- |
|
|
|
private static final Unsafe unsafe = Unsafe.getUnsafe(); |
|
|
|
private static byte _get(long a) { |
|
return unsafe.getByte(a); |
|
} |
|
|
|
private static void _put(long a, byte b) { |
|
unsafe.putByte(a, b); |
|
} |
|
|
|
static Unsafe unsafe() { |
|
return unsafe; |
|
} |
|
|
|
|
|
// -- Processor and memory-system properties -- |
|
|
|
private static final ByteOrder byteOrder; |
|
|
|
static ByteOrder byteOrder() { |
|
if (byteOrder == null) |
|
throw new Error("Unknown byte order"); |
|
return byteOrder; |
|
} |
|
|
|
static { |
|
long a = unsafe.allocateMemory(8); |
|
try { |
|
unsafe.putLong(a, 0x0102030405060708L); |
|
byte b = unsafe.getByte(a); |
|
switch (b) { |
|
case 0x01: byteOrder = ByteOrder.BIG_ENDIAN; break; |
|
case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN; break; |
|
default: |
|
assert false; |
|
byteOrder = null; |
|
} |
|
} finally { |
|
unsafe.freeMemory(a); |
|
} |
|
} |
|
|
|
|
|
private static int pageSize = -1; |
|
|
|
static int pageSize() { |
|
if (pageSize == -1) |
|
pageSize = unsafe().pageSize(); |
|
return pageSize; |
|
} |
|
|
|
static int pageCount(long size) { |
|
return (int)(size + (long)pageSize() - 1L) / pageSize(); |
|
} |
|
|
|
private static boolean unaligned; |
|
private static boolean unalignedKnown = false; |
|
|
|
static boolean unaligned() { |
|
if (unalignedKnown) |
|
return unaligned; |
|
String arch = AccessController.doPrivileged( |
|
new sun.security.action.GetPropertyAction("os.arch")); |
|
unaligned = arch.equals("i386") || arch.equals("x86") |
|
|| arch.equals("amd64") || arch.equals("x86_64") |
|
|| arch.equals("ppc64") || arch.equals("ppc64le") |
|
|| arch.equals("aarch64"); |
|
unalignedKnown = true; |
|
return unaligned; |
|
} |
|
|
|
|
|
// -- Direct memory management -- |
|
|
|
// A user-settable upper limit on the maximum amount of allocatable |
|
// direct buffer memory. This value may be changed during VM |
|
|
|
private static volatile long maxMemory = VM.maxDirectMemory(); |
|
private static final AtomicLong reservedMemory = new AtomicLong(); |
|
private static final AtomicLong totalCapacity = new AtomicLong(); |
|
private static final AtomicLong count = new AtomicLong(); |
|
private static volatile boolean memoryLimitSet = false; |
|
// max. number of sleeps during try-reserving with exponentially |
|
// increasing delay before throwing OutOfMemoryError: |
|
// 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s) |
|
|
|
private static final int MAX_SLEEPS = 9; |
|
|
|
// These methods should be called whenever direct memory is allocated or |
|
// freed. They allow the user to control the amount of direct memory |
|
|
|
static void reserveMemory(long size, int cap) { |
|
|
|
if (!memoryLimitSet && VM.isBooted()) { |
|
maxMemory = VM.maxDirectMemory(); |
|
memoryLimitSet = true; |
|
} |
|
|
|
|
|
if (tryReserveMemory(size, cap)) { |
|
return; |
|
} |
|
|
|
final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess(); |
|
|
|
// retry while helping enqueue pending Reference objects |
|
// which includes executing pending Cleaner(s) which includes |
|
|
|
while (jlra.tryHandlePendingReference()) { |
|
if (tryReserveMemory(size, cap)) { |
|
return; |
|
} |
|
} |
|
|
|
|
|
System.gc(); |
|
|
|
// a retry loop with exponential back-off delays |
|
|
|
boolean interrupted = false; |
|
try { |
|
long sleepTime = 1; |
|
int sleeps = 0; |
|
while (true) { |
|
if (tryReserveMemory(size, cap)) { |
|
return; |
|
} |
|
if (sleeps >= MAX_SLEEPS) { |
|
break; |
|
} |
|
if (!jlra.tryHandlePendingReference()) { |
|
try { |
|
Thread.sleep(sleepTime); |
|
sleepTime <<= 1; |
|
sleeps++; |
|
} catch (InterruptedException e) { |
|
interrupted = true; |
|
} |
|
} |
|
} |
|
|
|
|
|
throw new OutOfMemoryError("Direct buffer memory"); |
|
|
|
} finally { |
|
if (interrupted) { |
|
|
|
Thread.currentThread().interrupt(); |
|
} |
|
} |
|
} |
|
|
|
private static boolean tryReserveMemory(long size, int cap) { |
|
|
|
// -XX:MaxDirectMemorySize limits the total capacity rather than the |
|
// actual memory usage, which will differ when buffers are page |
|
|
|
long totalCap; |
|
while (cap <= maxMemory - (totalCap = totalCapacity.get())) { |
|
if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) { |
|
reservedMemory.addAndGet(size); |
|
count.incrementAndGet(); |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
static void unreserveMemory(long size, int cap) { |
|
long cnt = count.decrementAndGet(); |
|
long reservedMem = reservedMemory.addAndGet(-size); |
|
long totalCap = totalCapacity.addAndGet(-cap); |
|
assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0; |
|
} |
|
|
|
// -- Monitoring of direct buffer usage -- |
|
|
|
static { |
|
|
|
sun.misc.SharedSecrets.setJavaNioAccess( |
|
new sun.misc.JavaNioAccess() { |
|
@Override |
|
public sun.misc.JavaNioAccess.BufferPool getDirectBufferPool() { |
|
return new sun.misc.JavaNioAccess.BufferPool() { |
|
@Override |
|
public String getName() { |
|
return "direct"; |
|
} |
|
@Override |
|
public long getCount() { |
|
return Bits.count.get(); |
|
} |
|
@Override |
|
public long getTotalCapacity() { |
|
return Bits.totalCapacity.get(); |
|
} |
|
@Override |
|
public long getMemoryUsed() { |
|
return Bits.reservedMemory.get(); |
|
} |
|
}; |
|
} |
|
@Override |
|
public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) { |
|
return new DirectByteBuffer(addr, cap, ob); |
|
} |
|
@Override |
|
public void truncate(Buffer buf) { |
|
buf.truncate(); |
|
} |
|
}); |
|
} |
|
|
|
// -- Bulk get/put acceleration -- |
|
|
|
// These numbers represent the point at which we have empirically |
|
// determined that the average cost of a JNI call exceeds the expense |
|
|
|
static final int JNI_COPY_TO_ARRAY_THRESHOLD = 6; |
|
static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6; |
|
|
|
// This number limits the number of bytes to copy per call to Unsafe's |
|
// copyMemory method. A limit is imposed to allow for safepoint polling |
|
|
|
static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L; |
|
|
|
// These methods do no bounds checking. Verification that the copy will not |
|
// result in memory corruption should be done prior to invocation. |
|
// All positions and lengths are specified in bytes. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyFromArray(Object src, long srcBaseOffset, long srcPos, |
|
long dstAddr, long length) |
|
{ |
|
long offset = srcBaseOffset + srcPos; |
|
while (length > 0) { |
|
long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length; |
|
unsafe.copyMemory(src, offset, null, dstAddr, size); |
|
length -= size; |
|
offset += size; |
|
dstAddr += size; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyToArray(long srcAddr, Object dst, long dstBaseOffset, long dstPos, |
|
long length) |
|
{ |
|
long offset = dstBaseOffset + dstPos; |
|
while (length > 0) { |
|
long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length; |
|
unsafe.copyMemory(null, srcAddr, dst, offset, size); |
|
length -= size; |
|
srcAddr += size; |
|
offset += size; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyFromCharArray(Object src, long srcPos, long dstAddr, long length) { |
|
copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyToCharArray(long srcAddr, Object dst, long dstPos, long length) { |
|
copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyFromShortArray(Object src, long srcPos, long dstAddr, long length) { |
|
copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyToShortArray(long srcAddr, Object dst, long dstPos, long length) { |
|
copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyFromIntArray(Object src, long srcPos, long dstAddr, long length) { |
|
copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 4); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyToIntArray(long srcAddr, Object dst, long dstPos, long length) { |
|
copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 4); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyFromLongArray(Object src, long srcPos, long dstAddr, long length) { |
|
copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 8); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void copyToLongArray(long srcAddr, Object dst, long dstPos, long length) { |
|
copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 8); |
|
} |
|
|
|
private static boolean isPrimitiveArray(Class<?> c) { |
|
Class<?> componentType = c.getComponentType(); |
|
return componentType != null && componentType.isPrimitive(); |
|
} |
|
|
|
private native static void copySwapMemory0(Object srcBase, long srcOffset, |
|
Object destBase, long destOffset, |
|
long bytes, long elemSize); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static void copySwapMemory(Object srcBase, long srcOffset, |
|
Object destBase, long destOffset, |
|
long bytes, long elemSize) { |
|
if (bytes < 0) { |
|
throw new IllegalArgumentException(); |
|
} |
|
if (elemSize != 2 && elemSize != 4 && elemSize != 8) { |
|
throw new IllegalArgumentException(); |
|
} |
|
if (bytes % elemSize != 0) { |
|
throw new IllegalArgumentException(); |
|
} |
|
if ((srcBase == null && srcOffset == 0) || |
|
(destBase == null && destOffset == 0)) { |
|
throw new NullPointerException(); |
|
} |
|
|
|
|
|
if (srcBase != null && (srcOffset < 0 || !isPrimitiveArray(srcBase.getClass()))) { |
|
throw new IllegalArgumentException(); |
|
} |
|
if (destBase != null && (destOffset < 0 || !isPrimitiveArray(destBase.getClass()))) { |
|
throw new IllegalArgumentException(); |
|
} |
|
|
|
// Sanity check size and offsets on 32-bit platforms. Most |
|
|
|
if (unsafe.addressSize() == 4 && |
|
(bytes >>> 32 != 0 || srcOffset >>> 32 != 0 || destOffset >>> 32 != 0)) { |
|
throw new IllegalArgumentException(); |
|
} |
|
|
|
if (bytes == 0) { |
|
return; |
|
} |
|
|
|
copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize); |
|
} |
|
|
|
} |