Add *UnsafeHeapByteBuf for improve performance on systems with sun.misc.Unsafe

Motivation:

sun.misc.Unsafe allows us to handle heap ByteBuf in a more efficient matter. We should use special ByteBuf implementation when sun.misc.Unsafe can be used to increase performance.

Modifications:

- Add PooledUnsafeHeapByteBuf and UnpooledUnsafeHeapByteBuf that are used when sun.misc.Unsafe is ready to use.
- Add UnsafeHeapSwappedByteBuf

Result:

Better performance when using heap buffers and sun.misc.Unsafe is ready to use.
This commit is contained in:
Norman Maurer 2015-10-09 21:03:03 +02:00
parent f30a51b905
commit 7d4c077492
12 changed files with 724 additions and 183 deletions

View File

@ -0,0 +1,169 @@
/*
* Copyright 2015 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.buffer;
import io.netty.util.internal.PlatformDependent;
import java.nio.ByteOrder;
/**
* Special {@link SwappedByteBuf} for {@link ByteBuf}s that is using unsafe.
*/
abstract class AbstractUnsafeSwappedByteBuf extends SwappedByteBuf {
private final boolean nativeByteOrder;
private final AbstractByteBuf wrapped;
AbstractUnsafeSwappedByteBuf(AbstractByteBuf buf) {
super(buf);
assert PlatformDependent.isUnaligned();
wrapped = buf;
nativeByteOrder = UnsafeByteBufUtil.BIG_ENDIAN_NATIVE_ORDER == (order() == ByteOrder.BIG_ENDIAN);
}
@Override
public final long getLong(int index) {
wrapped.checkIndex(index, 8);
long v = _getLong(wrapped, index);
return nativeByteOrder ? v : Long.reverseBytes(v);
}
@Override
public final float getFloat(int index) {
return Float.intBitsToFloat(getInt(index));
}
@Override
public final double getDouble(int index) {
return Double.longBitsToDouble(getLong(index));
}
@Override
public final char getChar(int index) {
return (char) getShort(index);
}
@Override
public final long getUnsignedInt(int index) {
return getInt(index) & 0xFFFFFFFFL;
}
@Override
public final int getInt(int index) {
wrapped.checkIndex0(index, 4);
int v = _getInt(wrapped, index);
return nativeByteOrder ? v : Integer.reverseBytes(v);
}
@Override
public final int getUnsignedShort(int index) {
return getShort(index) & 0xFFFF;
}
@Override
public final short getShort(int index) {
wrapped.checkIndex0(index, 2);
short v = _getShort(wrapped, index);
return nativeByteOrder ? v : Short.reverseBytes(v);
}
@Override
public final ByteBuf setShort(int index, int value) {
wrapped.checkIndex0(index, 2);
_setShort(wrapped, index, nativeByteOrder ? (short) value : Short.reverseBytes((short) value));
return this;
}
@Override
public final ByteBuf setInt(int index, int value) {
wrapped.checkIndex0(index, 4);
_setInt(wrapped, index, nativeByteOrder ? value : Integer.reverseBytes(value));
return this;
}
@Override
public final ByteBuf setLong(int index, long value) {
wrapped.checkIndex(index, 8);
_setLong(wrapped, index, nativeByteOrder ? value : Long.reverseBytes(value));
return this;
}
@Override
public final ByteBuf setChar(int index, int value) {
setShort(index, value);
return this;
}
@Override
public final ByteBuf setFloat(int index, float value) {
setInt(index, Float.floatToRawIntBits(value));
return this;
}
@Override
public final ByteBuf setDouble(int index, double value) {
setLong(index, Double.doubleToRawLongBits(value));
return this;
}
@Override
public final ByteBuf writeShort(int value) {
wrapped.ensureWritable(2);
_setShort(wrapped, wrapped.writerIndex, nativeByteOrder ? (short) value : Short.reverseBytes((short) value));
wrapped.writerIndex += 2;
return this;
}
@Override
public final ByteBuf writeInt(int value) {
wrapped.ensureWritable(4);
_setInt(wrapped, wrapped.writerIndex, nativeByteOrder ? value : Integer.reverseBytes(value));
wrapped.writerIndex += 4;
return this;
}
@Override
public final ByteBuf writeLong(long value) {
wrapped.ensureWritable(8);
_setLong(wrapped, wrapped.writerIndex, nativeByteOrder ? value : Long.reverseBytes(value));
wrapped.writerIndex += 8;
return this;
}
@Override
public final ByteBuf writeChar(int value) {
writeShort(value);
return this;
}
@Override
public final ByteBuf writeFloat(float value) {
writeInt(Float.floatToRawIntBits(value));
return this;
}
@Override
public final ByteBuf writeDouble(double value) {
writeLong(Double.doubleToRawLongBits(value));
return this;
}
protected abstract short _getShort(AbstractByteBuf wrapped, int index);
protected abstract int _getInt(AbstractByteBuf wrapped, int index);
protected abstract long _getLong(AbstractByteBuf wrapped, int index);
protected abstract void _setShort(AbstractByteBuf wrapped, int index, short value);
protected abstract void _setInt(AbstractByteBuf wrapped, int index, int value);
protected abstract void _setLong(AbstractByteBuf wrapped, int index, long value);
}

View File

@ -26,6 +26,7 @@ import java.util.Collections;
import java.util.List;
abstract class PoolArena<T> implements PoolArenaMetric {
static final boolean HAS_UNSAFE = PlatformDependent.hasUnsafe();
enum SizeClass {
Tiny,
@ -614,7 +615,8 @@ abstract class PoolArena<T> implements PoolArenaMetric {
@Override
protected PooledByteBuf<byte[]> newByteBuf(int maxCapacity) {
return PooledHeapByteBuf.newInstance(maxCapacity);
return HAS_UNSAFE ? PooledUnsafeHeapByteBuf.newUnsafeInstance(maxCapacity)
: PooledHeapByteBuf.newInstance(maxCapacity);
}
@Override
@ -629,8 +631,6 @@ abstract class PoolArena<T> implements PoolArenaMetric {
static final class DirectArena extends PoolArena<ByteBuffer> {
private static final boolean HAS_UNSAFE = PlatformDependent.hasUnsafe();
DirectArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize) {
super(parent, pageSize, maxOrder, pageShifts, chunkSize);
}

View File

@ -25,7 +25,7 @@ import java.nio.channels.ClosedChannelException;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
private static final Recycler<PooledHeapByteBuf> RECYCLER = new Recycler<PooledHeapByteBuf>() {
@Override
@ -40,12 +40,12 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
return buf;
}
private PooledHeapByteBuf(Recycler.Handle<PooledHeapByteBuf> recyclerHandle, int maxCapacity) {
PooledHeapByteBuf(Recycler.Handle<? extends PooledHeapByteBuf> recyclerHandle, int maxCapacity) {
super(recyclerHandle, maxCapacity);
}
@Override
public boolean isDirect() {
public final boolean isDirect() {
return false;
}
@ -91,7 +91,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
public final ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
checkDstIndex(index, length, dstIndex, dst.capacity());
if (dst.hasMemoryAddress()) {
PlatformDependent.copyMemory(memory, idx(index), dst.memoryAddress() + dstIndex, length);
@ -104,28 +104,28 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
public final ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
checkDstIndex(index, length, dstIndex, dst.length);
System.arraycopy(memory, idx(index), dst, dstIndex, length);
return this;
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
public final ByteBuf getBytes(int index, ByteBuffer dst) {
checkIndex(index);
dst.put(memory, idx(index), Math.min(capacity() - index, dst.remaining()));
return this;
}
@Override
public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
public final ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
checkIndex(index, length);
out.write(memory, idx(index), length);
return this;
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
public final int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
return getBytes(index, out, length, false);
}
@ -142,7 +142,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public int readBytes(GatheringByteChannel out, int length) throws IOException {
public final int readBytes(GatheringByteChannel out, int length) throws IOException {
checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, length, true);
readerIndex += readBytes;
@ -192,7 +192,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
public final ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.capacity());
if (src.hasMemoryAddress()) {
PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, memory, idx(index), length);
@ -205,14 +205,14 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
public final ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
checkSrcIndex(index, length, srcIndex, src.length);
System.arraycopy(src, srcIndex, memory, idx(index), length);
return this;
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
public final ByteBuf setBytes(int index, ByteBuffer src) {
int length = src.remaining();
checkIndex(index, length);
src.get(memory, idx(index), length);
@ -220,13 +220,13 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public int setBytes(int index, InputStream in, int length) throws IOException {
public final int setBytes(int index, InputStream in, int length) throws IOException {
checkIndex(index, length);
return in.read(memory, idx(index), length);
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
public final int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
checkIndex(index, length);
index = idx(index);
try {
@ -237,7 +237,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public ByteBuf copy(int index, int length) {
public final ByteBuf copy(int index, int length) {
checkIndex(index, length);
ByteBuf copy = alloc().heapBuffer(length, maxCapacity());
copy.writeBytes(memory, idx(index), length);
@ -245,17 +245,17 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public int nioBufferCount() {
public final int nioBufferCount() {
return 1;
}
@Override
public ByteBuffer[] nioBuffers(int index, int length) {
public final ByteBuffer[] nioBuffers(int index, int length) {
return new ByteBuffer[] { nioBuffer(index, length) };
}
@Override
public ByteBuffer nioBuffer(int index, int length) {
public final ByteBuffer nioBuffer(int index, int length) {
checkIndex(index, length);
index = idx(index);
ByteBuffer buf = ByteBuffer.wrap(memory, index, length);
@ -263,40 +263,40 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
}
@Override
public ByteBuffer internalNioBuffer(int index, int length) {
public final ByteBuffer internalNioBuffer(int index, int length) {
checkIndex(index, length);
index = idx(index);
return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
}
@Override
public boolean hasArray() {
public final boolean hasArray() {
return true;
}
@Override
public byte[] array() {
public final byte[] array() {
ensureAccessible();
return memory;
}
@Override
public int arrayOffset() {
public final int arrayOffset() {
return offset;
}
@Override
public boolean hasMemoryAddress() {
public final boolean hasMemoryAddress() {
return false;
}
@Override
public long memoryAddress() {
public final long memoryAddress() {
throw new UnsupportedOperationException();
}
@Override
protected ByteBuffer newInternalNioBuffer(byte[] memory) {
protected final ByteBuffer newInternalNioBuffer(byte[] memory) {
return ByteBuffer.wrap(memory);
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file tothe 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.buffer;
import io.netty.util.Recycler;
import io.netty.util.Recycler.Handle;
import io.netty.util.internal.PlatformDependent;
final class PooledUnsafeHeapByteBuf extends PooledHeapByteBuf {
private static final Recycler<PooledUnsafeHeapByteBuf> RECYCLER = new Recycler<PooledUnsafeHeapByteBuf>() {
@Override
protected PooledUnsafeHeapByteBuf newObject(Handle<PooledUnsafeHeapByteBuf> handle) {
return new PooledUnsafeHeapByteBuf(handle, 0);
}
};
static PooledUnsafeHeapByteBuf newUnsafeInstance(int maxCapacity) {
PooledUnsafeHeapByteBuf buf = RECYCLER.get();
buf.reuse(maxCapacity);
return buf;
}
private PooledUnsafeHeapByteBuf(Handle<PooledUnsafeHeapByteBuf> recyclerHandle, int maxCapacity) {
super(recyclerHandle, maxCapacity);
}
@Override
protected byte _getByte(int index) {
return UnsafeByteBufUtil.getByte(memory, idx(index));
}
@Override
protected short _getShort(int index) {
return UnsafeByteBufUtil.getShort(memory, idx(index));
}
@Override
protected int _getUnsignedMedium(int index) {
return UnsafeByteBufUtil.getUnsignedMedium(memory, idx(index));
}
@Override
protected int _getInt(int index) {
return UnsafeByteBufUtil.getInt(memory, idx(index));
}
@Override
protected long _getLong(int index) {
return UnsafeByteBufUtil.getLong(memory, idx(index));
}
@Override
protected void _setByte(int index, int value) {
UnsafeByteBufUtil.setByte(memory, idx(index), value);
}
@Override
protected void _setShort(int index, int value) {
UnsafeByteBufUtil.setShort(memory, idx(index), value);
}
@Override
protected void _setMedium(int index, int value) {
UnsafeByteBufUtil.setMedium(memory, idx(index), value);
}
@Override
protected void _setInt(int index, int value) {
UnsafeByteBufUtil.setInt(memory, idx(index), value);
}
@Override
protected void _setLong(int index, long value) {
UnsafeByteBufUtil.setLong(memory, idx(index), value);
}
@Override
protected SwappedByteBuf newSwappedByteBuf() {
if (PlatformDependent.isUnaligned()) {
// Only use if unaligned access is supported otherwise there is no gain.
return new UnsafeHeapSwappedByteBuf(this);
}
return super.newSwappedByteBuf();
}
}

View File

@ -40,7 +40,8 @@ public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
@Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
return new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
: new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
}
@Override

View File

@ -32,7 +32,7 @@ import java.nio.channels.ScatteringByteChannel;
public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
private final ByteBufAllocator alloc;
private byte[] array;
byte[] array;
private ByteBuffer tmpNioBuf;
/**

View File

@ -0,0 +1,156 @@
/*
* Copyright 2015 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.buffer;
import io.netty.util.internal.PlatformDependent;
final class UnpooledUnsafeHeapByteBuf extends UnpooledHeapByteBuf {
/**
* Creates a new heap buffer with a newly allocated byte array.
*
* @param initialCapacity the initial capacity of the underlying byte array
* @param maxCapacity the max capacity of the underlying byte array
*/
UnpooledUnsafeHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
super(alloc, initialCapacity, maxCapacity);
}
@Override
public byte getByte(int index) {
checkIndex(index);
return _getByte(index);
}
@Override
protected byte _getByte(int index) {
return UnsafeByteBufUtil.getByte(array, index);
}
@Override
public short getShort(int index) {
checkIndex(index, 2);
return _getShort(index);
}
@Override
protected short _getShort(int index) {
return UnsafeByteBufUtil.getShort(array, index);
}
@Override
public int getUnsignedMedium(int index) {
checkIndex(index, 3);
return _getUnsignedMedium(index);
}
@Override
protected int _getUnsignedMedium(int index) {
return UnsafeByteBufUtil.getUnsignedMedium(array, index);
}
@Override
public int getInt(int index) {
checkIndex(index, 4);
return _getInt(index);
}
@Override
protected int _getInt(int index) {
return UnsafeByteBufUtil.getInt(array, index);
}
@Override
public long getLong(int index) {
checkIndex(index, 8);
return _getLong(index);
}
@Override
protected long _getLong(int index) {
return UnsafeByteBufUtil.getLong(array, index);
}
@Override
public ByteBuf setByte(int index, int value) {
checkIndex(index);
_setByte(index, value);
return this;
}
@Override
protected void _setByte(int index, int value) {
UnsafeByteBufUtil.setByte(array, index, value);
}
@Override
public ByteBuf setShort(int index, int value) {
checkIndex(index, 2);
_setShort(index, value);
return this;
}
@Override
protected void _setShort(int index, int value) {
UnsafeByteBufUtil.setShort(array, index, value);
}
@Override
public ByteBuf setMedium(int index, int value) {
checkIndex(index, 3);
_setMedium(index, value);
return this;
}
@Override
protected void _setMedium(int index, int value) {
UnsafeByteBufUtil.setMedium(array, index, value);
}
@Override
public ByteBuf setInt(int index, int value) {
checkIndex(index, 4);
_setInt(index, value);
return this;
}
@Override
protected void _setInt(int index, int value) {
UnsafeByteBufUtil.setInt(array, index, value);
}
@Override
public ByteBuf setLong(int index, long value) {
checkIndex(index, 8);
_setLong(index, value);
return this;
}
@Override
protected void _setLong(int index, long value) {
UnsafeByteBufUtil.setLong(array, index, value);
}
@Override
protected SwappedByteBuf newSwappedByteBuf() {
if (PlatformDependent.isUnaligned()) {
// Only use if unaligned access is supported otherwise there is no gain.
return new UnsafeHeapSwappedByteBuf(this);
}
return super.newSwappedByteBuf();
}
}

View File

@ -24,7 +24,7 @@ import java.nio.ByteOrder;
*/
final class UnsafeByteBufUtil {
private static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
static final boolean BIG_ENDIAN_NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
private static final boolean UNALIGNED = PlatformDependent.isUnaligned();
static byte getByte(long address) {
@ -34,14 +34,14 @@ final class UnsafeByteBufUtil {
static short getShort(long address) {
if (UNALIGNED) {
short v = PlatformDependent.getShort(address);
return NATIVE_ORDER ? v : Short.reverseBytes(v);
return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
}
return (short) (PlatformDependent.getByte(address) << 8 | PlatformDependent.getByte(address + 1) & 0xff);
}
static int getUnsignedMedium(long address) {
if (UNALIGNED) {
if (NATIVE_ORDER) {
if (BIG_ENDIAN_NATIVE_ORDER) {
return (PlatformDependent.getByte(address) & 0xff) |
(PlatformDependent.getShort(address + 1) & 0xffff) << 8;
}
@ -56,7 +56,7 @@ final class UnsafeByteBufUtil {
static int getInt(long address) {
if (UNALIGNED) {
int v = PlatformDependent.getInt(address);
return NATIVE_ORDER ? v : Integer.reverseBytes(v);
return BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
}
return PlatformDependent.getByte(address) << 24 |
(PlatformDependent.getByte(address + 1) & 0xff) << 16 |
@ -67,7 +67,7 @@ final class UnsafeByteBufUtil {
static long getLong(long address) {
if (UNALIGNED) {
long v = PlatformDependent.getLong(address);
return NATIVE_ORDER ? v : Long.reverseBytes(v);
return BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
}
return (long) PlatformDependent.getByte(address) << 56 |
((long) PlatformDependent.getByte(address + 1) & 0xff) << 48 |
@ -85,7 +85,8 @@ final class UnsafeByteBufUtil {
static void setShort(long address, int value) {
if (UNALIGNED) {
PlatformDependent.putShort(address, NATIVE_ORDER ? (short) value : Short.reverseBytes((short) value));
PlatformDependent.putShort(
address, BIG_ENDIAN_NATIVE_ORDER ? (short) value : Short.reverseBytes((short) value));
} else {
PlatformDependent.putByte(address, (byte) (value >>> 8));
PlatformDependent.putByte(address + 1, (byte) value);
@ -94,7 +95,7 @@ final class UnsafeByteBufUtil {
static void setMedium(long address, int value) {
if (UNALIGNED) {
if (NATIVE_ORDER) {
if (BIG_ENDIAN_NATIVE_ORDER) {
PlatformDependent.putByte(address, (byte) value);
PlatformDependent.putShort(address + 1, (short) (value >>> 8));
} else {
@ -110,7 +111,7 @@ final class UnsafeByteBufUtil {
static void setInt(long address, int value) {
if (UNALIGNED) {
PlatformDependent.putInt(address, NATIVE_ORDER ? value : Integer.reverseBytes(value));
PlatformDependent.putInt(address, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
} else {
PlatformDependent.putByte(address, (byte) (value >>> 24));
PlatformDependent.putByte(address + 1, (byte) (value >>> 16));
@ -121,7 +122,7 @@ final class UnsafeByteBufUtil {
static void setLong(long address, long value) {
if (UNALIGNED) {
PlatformDependent.putLong(address, NATIVE_ORDER ? value : Long.reverseBytes(value));
PlatformDependent.putLong(address, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
} else {
PlatformDependent.putByte(address, (byte) (value >>> 56));
PlatformDependent.putByte(address + 1, (byte) (value >>> 48));
@ -134,5 +135,113 @@ final class UnsafeByteBufUtil {
}
}
static byte getByte(byte[] array, int index) {
return PlatformDependent.getByte(array, index);
}
static short getShort(byte[] array, int index) {
if (UNALIGNED) {
short v = PlatformDependent.getShort(array, index);
return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
}
return (short) (PlatformDependent.getByte(index) << 8 | PlatformDependent.getByte(index + 1) & 0xff);
}
static int getUnsignedMedium(byte[] array, int index) {
if (UNALIGNED) {
if (BIG_ENDIAN_NATIVE_ORDER) {
return (PlatformDependent.getByte(array, index) & 0xff) |
(PlatformDependent.getShort(array, index + 1) & 0xffff) << 8;
}
return (Short.reverseBytes(PlatformDependent.getShort(array, index)) & 0xffff) << 8 |
PlatformDependent.getByte(array, index + 2) & 0xff;
}
return (PlatformDependent.getByte(array, index) & 0xff) << 16 |
(PlatformDependent.getByte(array, index + 1) & 0xff) << 8 |
PlatformDependent.getByte(array, index + 2) & 0xff;
}
static int getInt(byte[] array, int index) {
if (UNALIGNED) {
int v = PlatformDependent.getInt(array, index);
return BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
}
return PlatformDependent.getByte(array, index) << 24 |
(PlatformDependent.getByte(array, index + 1) & 0xff) << 16 |
(PlatformDependent.getByte(array, index + 2) & 0xff) << 8 |
PlatformDependent.getByte(array, index + 3) & 0xff;
}
static long getLong(byte[] array, int index) {
if (UNALIGNED) {
long v = PlatformDependent.getLong(array, index);
return BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
}
return (long) PlatformDependent.getByte(array, index) << 56 |
((long) PlatformDependent.getByte(array, index + 1) & 0xff) << 48 |
((long) PlatformDependent.getByte(array, index + 2) & 0xff) << 40 |
((long) PlatformDependent.getByte(array, index + 3) & 0xff) << 32 |
((long) PlatformDependent.getByte(array, index + 4) & 0xff) << 24 |
((long) PlatformDependent.getByte(array, index + 5) & 0xff) << 16 |
((long) PlatformDependent.getByte(array, index + 6) & 0xff) << 8 |
(long) PlatformDependent.getByte(array, index + 7) & 0xff;
}
static void setByte(byte[] array, int index, int value) {
PlatformDependent.putByte(array, index, (byte) value);
}
static void setShort(byte[] array, int index, int value) {
if (UNALIGNED) {
PlatformDependent.putShort(
array, index, BIG_ENDIAN_NATIVE_ORDER ? (short) value : Short.reverseBytes((short) value));
} else {
PlatformDependent.putByte(array, index, (byte) (value >>> 8));
PlatformDependent.putByte(array, index + 1, (byte) value);
}
}
static void setMedium(byte[] array, int index, int value) {
if (UNALIGNED) {
if (BIG_ENDIAN_NATIVE_ORDER) {
PlatformDependent.putByte(array, index, (byte) value);
PlatformDependent.putShort(array, index + 1, (short) (value >>> 8));
} else {
PlatformDependent.putShort(array, index, Short.reverseBytes((short) (value >>> 8)));
PlatformDependent.putByte(array, index + 2, (byte) value);
}
} else {
PlatformDependent.putByte(array, index, (byte) (value >>> 16));
PlatformDependent.putByte(array, index + 1, (byte) (value >>> 8));
PlatformDependent.putByte(array, index + 2, (byte) value);
}
}
static void setInt(byte[] array, int index, int value) {
if (UNALIGNED) {
PlatformDependent.putInt(array, index, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
} else {
PlatformDependent.putByte(array, index, (byte) (value >>> 24));
PlatformDependent.putByte(array, index + 1, (byte) (value >>> 16));
PlatformDependent.putByte(array, index + 2, (byte) (value >>> 8));
PlatformDependent.putByte(array, index + 3, (byte) value);
}
}
static void setLong(byte[] array, int index, long value) {
if (UNALIGNED) {
PlatformDependent.putLong(array, index, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
} else {
PlatformDependent.putByte(array, index, (byte) (value >>> 56));
PlatformDependent.putByte(array, index + 1, (byte) (value >>> 48));
PlatformDependent.putByte(array, index + 2, (byte) (value >>> 40));
PlatformDependent.putByte(array, index + 3, (byte) (value >>> 32));
PlatformDependent.putByte(array, index + 4, (byte) (value >>> 24));
PlatformDependent.putByte(array, index + 5, (byte) (value >>> 16));
PlatformDependent.putByte(array, index + 6, (byte) (value >>> 8));
PlatformDependent.putByte(array, index + 7, (byte) value);
}
}
private UnsafeByteBufUtil() { }
}

View File

@ -18,24 +18,16 @@ package io.netty.buffer;
import io.netty.util.internal.PlatformDependent;
import java.nio.ByteOrder;
/**
* Special {@link SwappedByteBuf} for {@link ByteBuf}s that are backed by a {@code memoryAddress}.
*/
final class UnsafeDirectSwappedByteBuf extends SwappedByteBuf {
private static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
private final boolean nativeByteOrder;
private final AbstractByteBuf wrapped;
final class UnsafeDirectSwappedByteBuf extends AbstractUnsafeSwappedByteBuf {
UnsafeDirectSwappedByteBuf(AbstractByteBuf buf) {
super(buf);
assert PlatformDependent.isUnaligned();
wrapped = buf;
nativeByteOrder = NATIVE_ORDER == (order() == ByteOrder.BIG_ENDIAN);
}
private long addr(int index) {
private static long addr(AbstractByteBuf wrapped, int index) {
// We need to call wrapped.memoryAddress() everytime and NOT cache it as it may change if the buffer expand.
// See:
// - https://github.com/netty/netty/issues/2587
@ -44,144 +36,32 @@ final class UnsafeDirectSwappedByteBuf extends SwappedByteBuf {
}
@Override
public long getLong(int index) {
wrapped.checkIndex(index, 8);
long v = PlatformDependent.getLong(addr(index));
return nativeByteOrder? v : Long.reverseBytes(v);
protected long _getLong(AbstractByteBuf wrapped, int index) {
return PlatformDependent.getLong(addr(wrapped, index));
}
@Override
public float getFloat(int index) {
return Float.intBitsToFloat(getInt(index));
protected int _getInt(AbstractByteBuf wrapped, int index) {
return PlatformDependent.getInt(addr(wrapped, index));
}
@Override
public double getDouble(int index) {
return Double.longBitsToDouble(getLong(index));
protected short _getShort(AbstractByteBuf wrapped, int index) {
return PlatformDependent.getShort(addr(wrapped, index));
}
@Override
public char getChar(int index) {
return (char) getShort(index);
protected void _setShort(AbstractByteBuf wrapped, int index, short value) {
PlatformDependent.putShort(addr(wrapped, index), value);
}
@Override
public long getUnsignedInt(int index) {
return getInt(index) & 0xFFFFFFFFL;
protected void _setInt(AbstractByteBuf wrapped, int index, int value) {
PlatformDependent.putInt(addr(wrapped, index), value);
}
@Override
public int getInt(int index) {
wrapped.checkIndex(index, 4);
int v = PlatformDependent.getInt(addr(index));
return nativeByteOrder? v : Integer.reverseBytes(v);
}
@Override
public int getUnsignedShort(int index) {
return getShort(index) & 0xFFFF;
}
@Override
public short getShort(int index) {
wrapped.checkIndex(index, 2);
short v = PlatformDependent.getShort(addr(index));
return nativeByteOrder? v : Short.reverseBytes(v);
}
@Override
public ByteBuf setShort(int index, int value) {
wrapped.checkIndex(index, 2);
_setShort(index, value);
return this;
}
@Override
public ByteBuf setInt(int index, int value) {
wrapped.checkIndex(index, 4);
_setInt(index, value);
return this;
}
@Override
public ByteBuf setLong(int index, long value) {
wrapped.checkIndex(index, 8);
_setLong(index, value);
return this;
}
@Override
public ByteBuf setChar(int index, int value) {
setShort(index, value);
return this;
}
@Override
public ByteBuf setFloat(int index, float value) {
setInt(index, Float.floatToRawIntBits(value));
return this;
}
@Override
public ByteBuf setDouble(int index, double value) {
setLong(index, Double.doubleToRawLongBits(value));
return this;
}
@Override
public ByteBuf writeShort(int value) {
wrapped.ensureAccessible();
wrapped.ensureWritable(2);
_setShort(wrapped.writerIndex, value);
wrapped.writerIndex += 2;
return this;
}
@Override
public ByteBuf writeInt(int value) {
wrapped.ensureAccessible();
wrapped.ensureWritable(4);
_setInt(wrapped.writerIndex, value);
wrapped.writerIndex += 4;
return this;
}
@Override
public ByteBuf writeLong(long value) {
wrapped.ensureAccessible();
wrapped.ensureWritable(8);
_setLong(wrapped.writerIndex, value);
wrapped.writerIndex += 8;
return this;
}
@Override
public ByteBuf writeChar(int value) {
writeShort(value);
return this;
}
@Override
public ByteBuf writeFloat(float value) {
writeInt(Float.floatToRawIntBits(value));
return this;
}
@Override
public ByteBuf writeDouble(double value) {
writeLong(Double.doubleToRawLongBits(value));
return this;
}
private void _setShort(int index, int value) {
PlatformDependent.putShort(addr(index), nativeByteOrder ? (short) value : Short.reverseBytes((short) value));
}
private void _setInt(int index, int value) {
PlatformDependent.putInt(addr(index), nativeByteOrder ? value : Integer.reverseBytes(value));
}
private void _setLong(int index, long value) {
PlatformDependent.putLong(addr(index), nativeByteOrder ? value : Long.reverseBytes(value));
protected void _setLong(AbstractByteBuf wrapped, int index, long value) {
PlatformDependent.putLong(addr(wrapped, index), value);
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2014 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.buffer;
import io.netty.util.internal.PlatformDependent;
/**
* Special {@link SwappedByteBuf} for {@link ByteBuf}s that use unsafe to access the byte array.
*/
final class UnsafeHeapSwappedByteBuf extends AbstractUnsafeSwappedByteBuf {
UnsafeHeapSwappedByteBuf(AbstractByteBuf buf) {
super(buf);
}
private static int idx(ByteBuf wrapped, int index) {
return wrapped.arrayOffset() + index;
}
@Override
protected long _getLong(AbstractByteBuf wrapped, int index) {
return PlatformDependent.getLong(wrapped.array(), idx(wrapped, index));
}
@Override
protected int _getInt(AbstractByteBuf wrapped, int index) {
return PlatformDependent.getInt(wrapped.array(), idx(wrapped, index));
}
@Override
protected short _getShort(AbstractByteBuf wrapped, int index) {
return PlatformDependent.getShort(wrapped.array(), idx(wrapped, index));
}
@Override
protected void _setShort(AbstractByteBuf wrapped, int index, short value) {
PlatformDependent.putShort(wrapped.array(), idx(wrapped, index), value);
}
@Override
protected void _setInt(AbstractByteBuf wrapped, int index, int value) {
PlatformDependent.putInt(wrapped.array(), idx(wrapped, index), value);
}
@Override
protected void _setLong(AbstractByteBuf wrapped, int index, long value) {
PlatformDependent.putLong(wrapped.array(), idx(wrapped, index), value);
}
}

View File

@ -30,6 +30,7 @@ import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Deque;
import java.util.List;
import java.util.Locale;
@ -77,7 +78,7 @@ public final class PlatformDependent {
HAS_UNSAFE && !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect", false);
private static final long MAX_DIRECT_MEMORY = maxDirectMemory0();
private static final long ARRAY_BASE_OFFSET = PlatformDependent0.arrayBaseOffset();
private static final long BYTE_ARRAY_BASE_OFFSET = PlatformDependent0.byteArrayBaseOffset();
private static final boolean HAS_JAVASSIST = hasJavassist0();
@ -86,6 +87,7 @@ public final class PlatformDependent {
private static final int BIT_MODE = bitMode0();
private static final int ADDRESS_SIZE = addressSize0();
private static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
static {
if (logger.isDebugEnabled()) {
@ -343,6 +345,22 @@ public final class PlatformDependent {
return PlatformDependent0.getLong(address);
}
public static byte getByte(byte[] data, int index) {
return PlatformDependent0.getByte(data, index);
}
public static short getShort(byte[] data, int index) {
return PlatformDependent0.getShort(data, index);
}
public static int getInt(byte[] data, int index) {
return PlatformDependent0.getInt(data, index);
}
public static long getLong(byte[] data, int index) {
return PlatformDependent0.getLong(data, index);
}
public static void putOrderedObject(Object object, long address, Object value) {
PlatformDependent0.putOrderedObject(object, address, value);
}
@ -363,16 +381,32 @@ public final class PlatformDependent {
PlatformDependent0.putLong(address, value);
}
public static void putByte(byte[] data, int index, byte value) {
PlatformDependent0.putByte(data, index, value);
}
public static void putShort(byte[] data, int index, short value) {
PlatformDependent0.putShort(data, index, value);
}
public static void putInt(byte[] data, int index, int value) {
PlatformDependent0.putInt(data, index, value);
}
public static void putLong(byte[] data, int index, long value) {
PlatformDependent0.putLong(data, index, value);
}
public static void copyMemory(long srcAddr, long dstAddr, long length) {
PlatformDependent0.copyMemory(srcAddr, dstAddr, length);
}
public static void copyMemory(byte[] src, int srcIndex, long dstAddr, long length) {
PlatformDependent0.copyMemory(src, ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
}
public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) {
PlatformDependent0.copyMemory(null, srcAddr, dst, ARRAY_BASE_OFFSET + dstIndex, length);
PlatformDependent0.copyMemory(null, srcAddr, dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
}
/**

View File

@ -39,7 +39,7 @@ final class PlatformDependent0 {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
static final Unsafe UNSAFE;
private static final long ADDRESS_FIELD_OFFSET;
private static final long ARRAY_BASE_OFFSET;
private static final long BYTE_ARRAY_BASE_OFFSET;
/**
* Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow safepoint polling
@ -108,11 +108,11 @@ final class PlatformDependent0 {
if (unsafe == null) {
ADDRESS_FIELD_OFFSET = -1;
ARRAY_BASE_OFFSET = -1;
BYTE_ARRAY_BASE_OFFSET = -1;
UNALIGNED = false;
} else {
ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
boolean unaligned;
try {
Class<?> bitsClass = Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader());
@ -158,8 +158,8 @@ final class PlatformDependent0 {
return getLong(buffer, ADDRESS_FIELD_OFFSET);
}
static long arrayBaseOffset() {
return ARRAY_BASE_OFFSET;
static long byteArrayBaseOffset() {
return BYTE_ARRAY_BASE_OFFSET;
}
static Object getObject(Object object, long fieldOffset) {
@ -198,6 +198,22 @@ final class PlatformDependent0 {
return UNSAFE.getLong(address);
}
static byte getByte(byte[] data, int index) {
return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
}
static short getShort(byte[] data, int index) {
return UNSAFE.getShort(data, BYTE_ARRAY_BASE_OFFSET + index);
}
static int getInt(byte[] data, int index) {
return UNSAFE.getInt(data, BYTE_ARRAY_BASE_OFFSET + index);
}
static long getLong(byte[] data, int index) {
return UNSAFE.getLong(data, BYTE_ARRAY_BASE_OFFSET + index);
}
static void putOrderedObject(Object object, long address, Object value) {
UNSAFE.putOrderedObject(object, address, value);
}
@ -218,6 +234,22 @@ final class PlatformDependent0 {
UNSAFE.putLong(address, value);
}
static void putByte(byte[] data, int index, byte value) {
UNSAFE.putByte(data, BYTE_ARRAY_BASE_OFFSET + index, value);
}
static void putShort(byte[] data, int index, short value) {
UNSAFE.putShort(data, BYTE_ARRAY_BASE_OFFSET + index, value);
}
static void putInt(byte[] data, int index, int value) {
UNSAFE.putInt(data, BYTE_ARRAY_BASE_OFFSET + index, value);
}
static void putLong(byte[] data, int index, long value) {
UNSAFE.putLong(data, BYTE_ARRAY_BASE_OFFSET + index, value);
}
static void copyMemory(long srcAddr, long dstAddr, long length) {
//UNSAFE.copyMemory(srcAddr, dstAddr, length);
while (length > 0) {
@ -249,8 +281,8 @@ final class PlatformDependent0 {
if (len1 == 0) {
return true;
}
final long baseOffset1 = ARRAY_BASE_OFFSET + startPos1;
final long baseOffset2 = ARRAY_BASE_OFFSET + startPos2;
final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
final long baseOffset2 = BYTE_ARRAY_BASE_OFFSET + startPos2;
int remainingBytes = len1 & 7;
for (int i = len1 - 8; i >= remainingBytes; i -= 8) {
if (UNSAFE.getLong(bytes1, baseOffset1 + i) != UNSAFE.getLong(bytes2, baseOffset2 + i)) {