io.netty.util.internal.PlatformDependent0 Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including
all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and
Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util.internal;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/**
* The {@link PlatformDependent} operations which requires access to {@code sun.misc.*}.
*/
final class PlatformDependent0 {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
private static final Unsafe UNSAFE;
private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
private static final long ADDRESS_FIELD_OFFSET;
/**
* Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow safepoint polling
* during a large copy.
*/
private static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
/**
* {@code true} if and only if the platform supports unaligned access.
*
* @see Wikipedia on segfault
*/
private static final boolean UNALIGNED;
static {
ByteBuffer direct = ByteBuffer.allocateDirect(1);
Field addressField;
try {
addressField = Buffer.class.getDeclaredField("address");
addressField.setAccessible(true);
if (addressField.getLong(ByteBuffer.allocate(1)) != 0) {
// A heap buffer must have 0 address.
addressField = null;
} else {
if (addressField.getLong(direct) == 0) {
// A direct buffer must have non-zero address.
addressField = null;
}
}
} catch (Throwable t) {
// Failed to access the address field.
addressField = null;
}
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
Unsafe unsafe;
if (addressField != null) {
try {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
unsafe = (Unsafe) unsafeField.get(null);
logger.debug("sun.misc.Unsafe.theUnsafe: {}", unsafe != null ? "available" : "unavailable");
// Ensure the unsafe supports all necessary methods to work around the mistake in the latest OpenJDK.
// https://github.com/netty/netty/issues/1061
// http://www.mail-archive.com/[email protected]/msg00698.html
try {
if (unsafe != null) {
unsafe.getClass().getDeclaredMethod(
"copyMemory", Object.class, long.class, Object.class, long.class, long.class);
logger.debug("sun.misc.Unsafe.copyMemory: available");
}
} catch (NoSuchMethodError t) {
logger.debug("sun.misc.Unsafe.copyMemory: unavailable");
throw t;
} catch (NoSuchMethodException e) {
logger.debug("sun.misc.Unsafe.copyMemory: unavailable");
throw e;
}
} catch (Throwable cause) {
// Unsafe.copyMemory(Object, long, Object, long, long) unavailable.
unsafe = null;
}
} else {
// If we cannot access the address of a direct buffer, there's no point of using unsafe.
// Let's just pretend unsafe is unavailable for overall simplicity.
unsafe = null;
}
UNSAFE = unsafe;
if (unsafe == null) {
ADDRESS_FIELD_OFFSET = -1;
UNALIGNED = false;
} else {
ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
boolean unaligned;
try {
Class> bitsClass = Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader());
Method unalignedMethod = bitsClass.getDeclaredMethod("unaligned");
unalignedMethod.setAccessible(true);
unaligned = Boolean.TRUE.equals(unalignedMethod.invoke(null));
} catch (Throwable t) {
// We at least know x86 and x64 support unaligned access.
String arch = SystemPropertyUtil.get("os.arch", "");
//noinspection DynamicRegexReplaceableByCompiledPattern
unaligned = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64)$");
}
UNALIGNED = unaligned;
logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED);
}
}
static boolean hasUnsafe() {
return UNSAFE != null;
}
static void throwException(Throwable t) {
UNSAFE.throwException(t);
}
static void freeDirectBuffer(ByteBuffer buffer) {
// Delegate to other class to not break on android
// See https://github.com/netty/netty/issues/2604
Cleaner0.freeDirectBuffer(buffer);
}
static long directBufferAddress(ByteBuffer buffer) {
return getLong(buffer, ADDRESS_FIELD_OFFSET);
}
static long arrayBaseOffset() {
return UNSAFE.arrayBaseOffset(byte[].class);
}
static Object getObject(Object object, long fieldOffset) {
return UNSAFE.getObject(object, fieldOffset);
}
static Object getObjectVolatile(Object object, long fieldOffset) {
return UNSAFE.getObjectVolatile(object, fieldOffset);
}
static int getInt(Object object, long fieldOffset) {
return UNSAFE.getInt(object, fieldOffset);
}
private static long getLong(Object object, long fieldOffset) {
return UNSAFE.getLong(object, fieldOffset);
}
static long objectFieldOffset(Field field) {
return UNSAFE.objectFieldOffset(field);
}
static byte getByte(long address) {
return UNSAFE.getByte(address);
}
static short getShort(long address) {
if (UNALIGNED) {
return UNSAFE.getShort(address);
} else if (BIG_ENDIAN) {
return (short) (getByte(address) << 8 | getByte(address + 1) & 0xff);
} else {
return (short) (getByte(address + 1) << 8 | getByte(address) & 0xff);
}
}
static int getInt(long address) {
if (UNALIGNED) {
return UNSAFE.getInt(address);
} else if (BIG_ENDIAN) {
return getByte(address) << 24 |
(getByte(address + 1) & 0xff) << 16 |
(getByte(address + 2) & 0xff) << 8 |
getByte(address + 3) & 0xff;
} else {
return getByte(address + 3) << 24 |
(getByte(address + 2) & 0xff) << 16 |
(getByte(address + 1) & 0xff) << 8 |
getByte(address) & 0xff;
}
}
static long getLong(long address) {
if (UNALIGNED) {
return UNSAFE.getLong(address);
} else if (BIG_ENDIAN) {
return (long) getByte(address) << 56 |
((long) getByte(address + 1) & 0xff) << 48 |
((long) getByte(address + 2) & 0xff) << 40 |
((long) getByte(address + 3) & 0xff) << 32 |
((long) getByte(address + 4) & 0xff) << 24 |
((long) getByte(address + 5) & 0xff) << 16 |
((long) getByte(address + 6) & 0xff) << 8 |
(long) getByte(address + 7) & 0xff;
} else {
return (long) getByte(address + 7) << 56 |
((long) getByte(address + 6) & 0xff) << 48 |
((long) getByte(address + 5) & 0xff) << 40 |
((long) getByte(address + 4) & 0xff) << 32 |
((long) getByte(address + 3) & 0xff) << 24 |
((long) getByte(address + 2) & 0xff) << 16 |
((long) getByte(address + 1) & 0xff) << 8 |
(long) getByte(address) & 0xff;
}
}
static void putOrderedObject(Object object, long address, Object value) {
UNSAFE.putOrderedObject(object, address, value);
}
static void putByte(long address, byte value) {
UNSAFE.putByte(address, value);
}
static void putShort(long address, short value) {
if (UNALIGNED) {
UNSAFE.putShort(address, value);
} else if (BIG_ENDIAN) {
putByte(address, (byte) (value >>> 8));
putByte(address + 1, (byte) value);
} else {
putByte(address + 1, (byte) (value >>> 8));
putByte(address, (byte) value);
}
}
static void putInt(long address, int value) {
if (UNALIGNED) {
UNSAFE.putInt(address, value);
} else if (BIG_ENDIAN) {
putByte(address, (byte) (value >>> 24));
putByte(address + 1, (byte) (value >>> 16));
putByte(address + 2, (byte) (value >>> 8));
putByte(address + 3, (byte) value);
} else {
putByte(address + 3, (byte) (value >>> 24));
putByte(address + 2, (byte) (value >>> 16));
putByte(address + 1, (byte) (value >>> 8));
putByte(address, (byte) value);
}
}
static void putLong(long address, long value) {
if (UNALIGNED) {
UNSAFE.putLong(address, value);
} else if (BIG_ENDIAN) {
putByte(address, (byte) (value >>> 56));
putByte(address + 1, (byte) (value >>> 48));
putByte(address + 2, (byte) (value >>> 40));
putByte(address + 3, (byte) (value >>> 32));
putByte(address + 4, (byte) (value >>> 24));
putByte(address + 5, (byte) (value >>> 16));
putByte(address + 6, (byte) (value >>> 8));
putByte(address + 7, (byte) value);
} else {
putByte(address + 7, (byte) (value >>> 56));
putByte(address + 6, (byte) (value >>> 48));
putByte(address + 5, (byte) (value >>> 40));
putByte(address + 4, (byte) (value >>> 32));
putByte(address + 3, (byte) (value >>> 24));
putByte(address + 2, (byte) (value >>> 16));
putByte(address + 1, (byte) (value >>> 8));
putByte(address, (byte) value);
}
}
static void copyMemory(long srcAddr, long dstAddr, long length) {
//UNSAFE.copyMemory(srcAddr, dstAddr, length);
while (length > 0) {
long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
UNSAFE.copyMemory(srcAddr, dstAddr, size);
length -= size;
srcAddr += size;
dstAddr += size;
}
}
static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
//UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
while (length > 0) {
long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
length -= size;
srcOffset += size;
dstOffset += size;
}
}
static AtomicReferenceFieldUpdater newAtomicReferenceFieldUpdater(
Class tclass, String fieldName) throws Exception {
return new UnsafeAtomicReferenceFieldUpdater(UNSAFE, tclass, fieldName);
}
static AtomicIntegerFieldUpdater newAtomicIntegerFieldUpdater(
Class> tclass, String fieldName) throws Exception {
return new UnsafeAtomicIntegerFieldUpdater(UNSAFE, tclass, fieldName);
}
static AtomicLongFieldUpdater newAtomicLongFieldUpdater(
Class> tclass, String fieldName) throws Exception {
return new UnsafeAtomicLongFieldUpdater(UNSAFE, tclass, fieldName);
}
static ClassLoader getClassLoader(final Class> clazz) {
if (System.getSecurityManager() == null) {
return clazz.getClassLoader();
} else {
return AccessController.doPrivileged(new PrivilegedAction() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
}
});
}
}
static ClassLoader getContextClassLoader() {
if (System.getSecurityManager() == null) {
return Thread.currentThread().getContextClassLoader();
} else {
return AccessController.doPrivileged(new PrivilegedAction() {
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
});
}
}
static ClassLoader getSystemClassLoader() {
if (System.getSecurityManager() == null) {
return ClassLoader.getSystemClassLoader();
} else {
return AccessController.doPrivileged(new PrivilegedAction() {
@Override
public ClassLoader run() {
return ClassLoader.getSystemClassLoader();
}
});
}
}
static int addressSize() {
return UNSAFE.addressSize();
}
static long allocateMemory(long size) {
return UNSAFE.allocateMemory(size);
}
static void freeMemory(long address) {
UNSAFE.freeMemory(address);
}
private PlatformDependent0() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy