Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.zodiac.sdk.nio.common.Unsafe Maven / Gradle / Ivy
package org.zodiac.sdk.nio.common;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
public class Unsafe {
public static final String ENABLE_UNSAFE = "platform.io.enable_unsafe";
public static final String ENABLE_UNSAFE_BUF = "platform.ssl.enable_unsafe_buf";
/**
* Size of int in bytes
*/
public static final int SIZEOF_INT = Integer.SIZE / Byte.SIZE;
/**
* Size of long in bytes
*/
public static final int SIZEOF_LONG = Long.SIZE / Byte.SIZE;
/**
* Size of short in bytes
*/
public static final int SIZEOF_SHORT = Short.SIZE / Byte.SIZE;
/** The offset to the first element in a byte array. */
public static final long BYTE_ARRAY_BASE_OFFSET;
public static final int BUF_UNSAFE = 0;
public static final int BUF_DIRECT = 1;
public static final int BUF_HEAP = 2;
public static final long ARRAY_BASE_OFFSET;
public static final long BUFFER_ADDRESS_OFFSET;
public static final boolean IS_LINUX = isLinux();
public static final boolean IS_ANDROID = isAndroid();
public static final boolean UNSAFE_AVAILABLE = isUnsafeAvailable();
public static final boolean UNSAFE_BUF_AVAILABLE;
public static final boolean DIRECT_BUFFER_AVAILABLE;
public static final boolean LITTLE_ENDIAN = ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN);
// This number limits the number of bytes to copy per call to Unsafe's
// copyMemory method. A writeIndex is imposed to allow for safe point polling
// during a large copy
private static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
private static final boolean BIG_ORDER = checkBigOrder();
private static final boolean RAW_DIRECT_AVAILABLE;
private static final int JAVA_VERSION = majorJavaVersion();
private static final Constructor> DIRECT_BUFFER_CONSTRUCTOR;
private static final int CAS_UPDATE_YIELD_TIME = 16;
private static final sun.misc.Unsafe JDK_UNSAFE;
// jdk.internal.misc.Unsafe
// jdk.internal.ref.Cleaner
static {
if (UNSAFE_AVAILABLE) {
JDK_UNSAFE = getJdkUnsafe();
BYTE_ARRAY_BASE_OFFSET = JDK_UNSAFE.arrayBaseOffset(byte[].class);
UNSAFE_BUF_AVAILABLE = isEnableUnsafeBuf();
BUFFER_ADDRESS_OFFSET = fieldOffset(getDeclaredField(Buffer.class, "address"));
DIRECT_BUFFER_AVAILABLE = BUFFER_ADDRESS_OFFSET != -1;
ARRAY_BASE_OFFSET = JDK_UNSAFE.arrayBaseOffset(byte[].class);
DIRECT_BUFFER_CONSTRUCTOR = getDirectBufferConstructor();
RAW_DIRECT_AVAILABLE = DIRECT_BUFFER_CONSTRUCTOR != null;
} else {
if (isEnableUnsafeBuf()) {
throw new Error("UnsafeBuf enabled but no unsafe available");
}
JDK_UNSAFE = null;
BYTE_ARRAY_BASE_OFFSET = -1;
UNSAFE_BUF_AVAILABLE = false;
BUFFER_ADDRESS_OFFSET = -1;
DIRECT_BUFFER_AVAILABLE = false;
ARRAY_BASE_OFFSET = -1;
DIRECT_BUFFER_CONSTRUCTOR = null;
RAW_DIRECT_AVAILABLE = false;
}
}
private Unsafe() {}
private static Constructor> getDirectBufferConstructor() {
Constructor> directBufferConstructor = null;
final ByteBuffer direct = ByteBuffer.allocateDirect(1);
long address = -1;
try {
final Object res = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Object run() {
try {
final Constructor> constructor =
direct.getClass().getDeclaredConstructor(long.class, int.class);
Throwable cause = trySetAccessible(constructor);
if (cause != null) {
return cause;
}
return constructor;
} catch (Throwable e) {
return e;
}
}
});
if (res instanceof Constructor>) {
address = allocate(1);
try {
((Constructor>)res).newInstance(address, 1);
directBufferConstructor = (Constructor>)res;
} catch (Throwable e) {
return null;
}
} else {
return null;
}
} finally {
if (address != -1) {
free(address);
}
}
return directBufferConstructor;
}
private static void checkUnsafeAvailable() {
if (!UNSAFE_AVAILABLE) {
throw new RuntimeException("Unsafe not available");
}
}
private static boolean isAndroid() {
return "Dalvik".equalsIgnoreCase(System.getProperty("java.vm.name"));
}
private static boolean isLinux() {
return System.getProperty("os.name", "").toLowerCase().startsWith("lin");
}
private static boolean isUnsafeAvailable() {
return !IS_ANDROID && isEnableUnsafe();
}
public static int addAndGetInt(Object object, int offset, int add) {
int expect = getIntVolatile(object, offset);
int update = expect + add;
if (compareAndSwapInt(object, offset, expect, update)) {
return update;
}
for (int i = 0; i < CAS_UPDATE_YIELD_TIME; i++) {
expect = getIntVolatile(object, offset);
update = expect + add;
if (compareAndSwapInt(object, offset, expect, update)) {
return update;
}
}
for (;;) {
expect = getIntVolatile(object, offset);
update = expect + add;
if (compareAndSwapInt(object, offset, expect, update)) {
return update;
} else {
Thread.yield();
}
}
}
public static long addAndGetLong(Object object, long offset, long add) {
long expect = getLongVolatile(object, offset);
long update = expect + add;
if (compareAndSwapLong(object, offset, expect, update)) {
return update;
}
for (int i = 0; i < CAS_UPDATE_YIELD_TIME; i++) {
expect = getLongVolatile(object, offset);
update = expect + add;
if (compareAndSwapLong(object, offset, expect, update)) {
return update;
}
}
for (;;) {
expect = getLongVolatile(object, offset);
update = expect + add;
if (compareAndSwapLong(object, offset, expect, update)) {
return update;
} else {
Thread.yield();
}
}
}
public static int getMemoryTypeId() {
if (UNSAFE_BUF_AVAILABLE) {
return BUF_UNSAFE;
} else if (DIRECT_BUFFER_AVAILABLE) {
return BUF_DIRECT;
} else {
return BUF_HEAP;
}
}
public static String getMemoryType() {
if (UNSAFE_BUF_AVAILABLE) {
return "unsafe";
} else if (DIRECT_BUFFER_AVAILABLE) {
return "direct";
} else {
return "heap";
}
}
public static long address(ByteBuffer buffer) {
checkUnsafeAvailable();
return JDK_UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
}
public static long allocate(long length) {
checkUnsafeAvailable();
return JDK_UNSAFE.allocateMemory(length);
}
public static Object allocateInstance(Class> clazz) {
checkUnsafeAvailable();
try {
return JDK_UNSAFE.allocateInstance(clazz);
} catch (InstantiationException e) {
throw new RuntimeException(e);
}
}
public static boolean compareAndSwapInt(Object o, long offset, int expect, int val) {
checkUnsafeAvailable();
return JDK_UNSAFE.compareAndSwapInt(o, offset, expect, val);
}
public static boolean compareAndSwapLong(Object o, long offset, long expect, long val) {
checkUnsafeAvailable();
return JDK_UNSAFE.compareAndSwapLong(o, offset, expect, val);
}
public static boolean compareAndSwapObject(Object o, long offset, Object expect, Object val) {
checkUnsafeAvailable();
return JDK_UNSAFE.compareAndSwapObject(o, offset, expect, val);
}
public static void putOrderedInt(Object o, long offset, int expect) {
checkUnsafeAvailable();
JDK_UNSAFE.putOrderedInt(o, offset, expect);
}
public static long objectFieldOffset(Field f) {
return JDK_UNSAFE.objectFieldOffset(f);
}
public static void throwException(Throwable t) {
JDK_UNSAFE.throwException(t);
}
public static void copyFromArray(byte[] src, long srcPos, long dstAddr, long length) {
checkUnsafeAvailable();
long offset = ARRAY_BASE_OFFSET + srcPos;
// JDK_UNSAFE.copyMemory(src, offset, null, dstAddr, length);
unsafeCopy(src, offset, null, dstAddr, length);
}
public static void copyMemory(long srcAddress, long targetAddress, long length) {
copyMemory(null, srcAddress, null, targetAddress, length);
}
public static void copyMemory(Object src, long srcOffset, Object target, long targetOffset, long length) {
checkUnsafeAvailable();
// see java.nio.Bits.copyToArray
if (length < UNSAFE_COPY_THRESHOLD) {
// JDK_UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
unsafeCopy(src, srcOffset, target, targetOffset, length);
} else {
for (; length > 0;) {
long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
// JDK_UNSAFE.copyMemory(src, srcOffset, target, targetOffset, size);
unsafeCopy(src, srcOffset, target, targetOffset, size);
length -= size;
srcOffset += size;
targetOffset += size;
}
}
}
public static void copyMemory(byte[] src, int srcOffset, ByteBuffer dest, int destOffset, int length) {
long destAddress = destOffset;
Object destBase = null;
if (dest.isDirect()) {
destAddress = destAddress + ((sun.nio.ch.DirectBuffer)dest).address();
} else {
destAddress = destAddress + BYTE_ARRAY_BASE_OFFSET + dest.arrayOffset();
destBase = dest.array();
}
long srcAddress = srcOffset + BYTE_ARRAY_BASE_OFFSET;
unsafeCopy(src, srcAddress, destBase, destAddress, length);
}
public static void copyToArray(long srcAddr, byte[] dst, long dstPos, long length) {
checkUnsafeAvailable();
long dstOffset = ARRAY_BASE_OFFSET + dstPos;
// JDK_UNSAFE.copyMemory(null, srcAddr, dst, dstOffset, length);
unsafeCopy(null, srcAddr, dst, dstOffset, length);
}
public static void free(long address) {
checkUnsafeAvailable();
JDK_UNSAFE.freeMemory(address);
}
public static long getArrayBaseOffset() {
return ARRAY_BASE_OFFSET;
}
public static boolean getBoolean(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getBoolean(target, offset);
}
public static boolean getBooleanVolatile(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getBooleanVolatile(target, offset);
}
public static byte getByte(long address) {
checkUnsafeAvailable();
return JDK_UNSAFE.getByte(address);
}
public static byte getByte(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getByte(target, offset);
}
public static double getDouble(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getDouble(target, offset);
}
public static float getFloat(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getFloat(target, offset);
}
public static int getInt(long address) {
checkUnsafeAvailable();
return JDK_UNSAFE.getInt(address);
}
public static int getInt(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getInt(target, offset);
}
public static int getIntVolatile(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getIntVolatile(target, offset);
}
public static long getLong(long address) {
checkUnsafeAvailable();
return JDK_UNSAFE.getLong(address);
}
public static long getLong(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getLong(target, offset);
}
public static long getLongVolatile(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getLongVolatile(target, offset);
}
public static Object getObject(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getObject(target, offset);
}
public static Object getObjectVolatile(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getObjectVolatile(target, offset);
}
public static short getShort(long address) {
checkUnsafeAvailable();
return JDK_UNSAFE.getShort(address);
}
public static short getShort(Object target, long offset) {
checkUnsafeAvailable();
return JDK_UNSAFE.getShort(target, offset);
}
private static boolean checkBigOrder() {
return ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
}
public static boolean isBigOrder() {
return BIG_ORDER;
}
public static boolean isLittleOrder() {
return !BIG_ORDER;
}
public static long fieldOffset(Field field) {
return field == null || JDK_UNSAFE == null ? -1 : JDK_UNSAFE.objectFieldOffset(field);
}
public static long fieldOffset(Class clazz, String fieldName) {
Field field = getDeclaredField(clazz, fieldName);
if (field == null) {
throw new RuntimeException("no such field: " + fieldName);
}
return fieldOffset(field);
}
public static void putBoolean(Object target, long offset, boolean value) {
checkUnsafeAvailable();
JDK_UNSAFE.putBoolean(target, offset, value);
}
public static void putBooleanVolatile(Object target, long offset, boolean value) {
checkUnsafeAvailable();
JDK_UNSAFE.putBooleanVolatile(target, offset, value);
}
public static void putByte(long address, byte value) {
checkUnsafeAvailable();
JDK_UNSAFE.putByte(address, value);
}
public static void putByte(Object target, long offset, byte value) {
checkUnsafeAvailable();
JDK_UNSAFE.putByte(target, offset, value);
}
public static void putDouble(Object target, long offset, double value) {
checkUnsafeAvailable();
JDK_UNSAFE.putDouble(target, offset, value);
}
public static void putFloat(Object target, long offset, float value) {
checkUnsafeAvailable();
JDK_UNSAFE.putFloat(target, offset, value);
}
public static void putInt(long address, int value) {
checkUnsafeAvailable();
JDK_UNSAFE.putInt(address, value);
}
public static void putInt(Object target, long offset, int value) {
checkUnsafeAvailable();
JDK_UNSAFE.putInt(target, offset, value);
}
public static int putInt(ByteBuffer buf, int offset, int val) {
if (buf.isDirect()) {
JDK_UNSAFE.putInt(((sun.nio.ch.DirectBuffer)buf).address() + offset, val);
} else {
JDK_UNSAFE.putInt(buf.array(), offset + buf.arrayOffset() + BYTE_ARRAY_BASE_OFFSET, val);
}
return offset + SIZEOF_INT;
}
public static void putIntVolatile(Object target, long offset, int value) {
checkUnsafeAvailable();
JDK_UNSAFE.putIntVolatile(target, offset, value);
}
public static void putLong(long address, long value) {
checkUnsafeAvailable();
JDK_UNSAFE.putLong(address, value);
}
public static void putLong(Object target, long offset, long value) {
checkUnsafeAvailable();
JDK_UNSAFE.putLong(target, offset, value);
}
public static int putLong(ByteBuffer buf, int offset, long val) {
checkUnsafeAvailable();
if (buf.isDirect()) {
JDK_UNSAFE.putLong(((sun.nio.ch.DirectBuffer)buf).address() + offset, val);
} else {
JDK_UNSAFE.putLong(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset, val);
}
return offset + SIZEOF_LONG;
}
public static void putLongVolatile(Object target, long offset, long value) {
checkUnsafeAvailable();
JDK_UNSAFE.putLongVolatile(target, offset, value);
}
public static void putObject(Object target, long offset, Object value) {
checkUnsafeAvailable();
JDK_UNSAFE.putObject(target, offset, value);
}
public static void putObjectVolatile(Object target, long offset, Object value) {
checkUnsafeAvailable();
JDK_UNSAFE.putObjectVolatile(target, offset, value);
}
public static void putShort(long address, short value) {
checkUnsafeAvailable();
JDK_UNSAFE.putShort(address, value);
}
public static void putShort(Object target, long offset, short value) {
checkUnsafeAvailable();
JDK_UNSAFE.putShort(target, offset, value);
}
public static int putShort(ByteBuffer buf, int offset, short val) {
if (buf.isDirect()) {
JDK_UNSAFE.putShort(((sun.nio.ch.DirectBuffer)buf).address() + offset, val);
} else {
JDK_UNSAFE.putShort(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset, val);
}
return offset + SIZEOF_SHORT;
}
public static short toShort(ByteBuffer buf, int offset) {
if (LITTLE_ENDIAN) {
return Short.reverseBytes(getAsShort(buf, offset));
}
return getAsShort(buf, offset);
}
public static int toInt(ByteBuffer buf, int offset) {
if (LITTLE_ENDIAN) {
return Integer.reverseBytes(getAsInt(buf, offset));
}
return getAsInt(buf, offset);
}
public static long toLong(ByteBuffer buf, int offset) {
if (LITTLE_ENDIAN) {
return Long.reverseBytes(getAsLong(buf, offset));
}
return getAsLong(buf, offset);
}
public static void setMemory(long address, long numBytes, byte value) {
checkUnsafeAvailable();
JDK_UNSAFE.setMemory(address, numBytes, value);
}
public static int javaVersion() {
return JAVA_VERSION;
}
public static ByteBuffer allocateDirectByteBuffer(int cap) {
if (RAW_DIRECT_AVAILABLE) {
long address = allocate(cap);
if (address == -1) {
throw new RuntimeException("no enough space(direct): " + cap);
}
try {
return (ByteBuffer)DIRECT_BUFFER_CONSTRUCTOR.newInstance(address, cap);
} catch (Throwable e) {
free(address);
throw new Error(e);
}
} else {
return ByteBuffer.allocateDirect(cap);
}
}
public static void freeByteBuffer(ByteBuffer buffer) {
if (buffer.isDirect()) {
if (((sun.nio.ch.DirectBuffer)buffer).cleaner() != null) {
((sun.nio.ch.DirectBuffer)buffer).cleaner().clean();
} else {
free(address(buffer));
}
}
}
static short getAsShort(ByteBuffer buf, int offset) {
if (buf.isDirect()) {
return JDK_UNSAFE.getShort(((sun.nio.ch.DirectBuffer)buf).address() + offset);
}
return JDK_UNSAFE.getShort(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
static int getAsInt(ByteBuffer buf, int offset) {
if (buf.isDirect()) {
return JDK_UNSAFE.getInt(((sun.nio.ch.DirectBuffer)buf).address() + offset);
}
return JDK_UNSAFE.getInt(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
static long getAsLong(ByteBuffer buf, int offset) {
if (buf.isDirect()) {
return JDK_UNSAFE.getLong(((sun.nio.ch.DirectBuffer)buf).address() + offset);
}
return JDK_UNSAFE.getLong(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
private static int majorJavaVersion() {
final String javaSpecVersion = System.getProperty("java.specification.version", "8");
final String[] components = javaSpecVersion.split("\\.");
final int[] version = new int[components.length];
for (int i = 0; i < components.length; i++) {
version[i] = Integer.parseInt(components[i]);
}
if (version[0] == 1) {
assert version[1] >= 6;
return version[1];
} else {
return version[0];
}
}
public static int arrayBaseOffset(Class> clazz) {
checkUnsafeAvailable();
return JDK_UNSAFE.arrayBaseOffset(clazz);
}
public static int arrayIndexScale(Class> clazz) {
checkUnsafeAvailable();
return JDK_UNSAFE.arrayIndexScale(clazz);
}
private static sun.misc.Unsafe getJdkUnsafe() {
try {
return AccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public sun.misc.Unsafe run() throws Exception {
Class k = sun.misc.Unsafe.class;
for (Field f : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x)) {
return k.cast(x);
}
}
// The sun.misc.Unsafe field does not exist.
throw new Error("unsafe is null");
}
});
} catch (Throwable e) {
throw new Error("get unsafe failed", e);
}
}
public static void putOrderedObject(Object target, long offset, Object value) {
checkUnsafeAvailable();
JDK_UNSAFE.putOrderedObject(target, offset, value);
}
public static Object getAndSetObject(Object target, long offset, Object value) {
checkUnsafeAvailable();
return JDK_UNSAFE.getAndSetObject(target, offset, value);
}
public static boolean isEnableUnsafe() {
return isTrue(ENABLE_UNSAFE, true);
}
public static boolean isEnableUnsafeBuf() {
return isTrue(ENABLE_UNSAFE_BUF);
}
public static Throwable trySetAccessible(AccessibleObject object) {
try {
object.setAccessible(true);
return null;
} catch (Throwable e) {
return e;
}
}
public static Field getDeclaredField(Class> clazz, String name) {
if (clazz == null) {
return null;
}
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
if (f.getName().equals(name)) {
return f;
}
}
return null;
}
private static boolean isTrue(String key) {
return isTrue(key, false);
}
private static boolean isTrue(String key, boolean def) {
String v = System.getProperty(key);
if (null == v || v.isEmpty()) {
return def;
}
return "1".equals(v) || "true".equals(v);
}
private static void unsafeCopy(Object src, long srcAddr, Object dst, long destAddr, long len) {
while (len > 0) {
long size = (len > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : len;
JDK_UNSAFE.copyMemory(src, srcAddr, dst, destAddr, size);
len -= size;
srcAddr += size;
destAddr += size;
}
}
public static void main(String[] args) {
System.out.println(System.getProperty("java.specification.version"));
}
}