From 164f6f1731fe37d27b3a3c456c81d714af27b443 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Fri, 9 Oct 2015 21:03:03 +0200 Subject: [PATCH] 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. --- .../buffer/AbstractUnsafeSwappedByteBuf.java | 169 ++++++++++++++++++ .../main/java/io/netty/buffer/PoolArena.java | 6 +- .../io/netty/buffer/PooledHeapByteBuf.java | 50 +++--- .../netty/buffer/PooledUnsafeHeapByteBuf.java | 102 +++++++++++ .../buffer/UnpooledByteBufAllocator.java | 3 +- .../io/netty/buffer/UnpooledHeapByteBuf.java | 2 +- .../buffer/UnpooledUnsafeHeapByteBuf.java | 156 ++++++++++++++++ .../io/netty/buffer/UnsafeByteBufUtil.java | 127 ++++++++++++- .../buffer/UnsafeDirectSwappedByteBuf.java | 148 ++------------- .../buffer/UnsafeHeapSwappedByteBuf.java | 63 +++++++ .../util/internal/PlatformDependent.java | 34 ++++ .../util/internal/PlatformDependent0.java | 35 ++++ 12 files changed, 722 insertions(+), 173 deletions(-) create mode 100644 buffer/src/main/java/io/netty/buffer/AbstractUnsafeSwappedByteBuf.java create mode 100644 buffer/src/main/java/io/netty/buffer/PooledUnsafeHeapByteBuf.java create mode 100644 buffer/src/main/java/io/netty/buffer/UnpooledUnsafeHeapByteBuf.java create mode 100644 buffer/src/main/java/io/netty/buffer/UnsafeHeapSwappedByteBuf.java diff --git a/buffer/src/main/java/io/netty/buffer/AbstractUnsafeSwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractUnsafeSwappedByteBuf.java new file mode 100644 index 0000000000..66ba5c3689 --- /dev/null +++ b/buffer/src/main/java/io/netty/buffer/AbstractUnsafeSwappedByteBuf.java @@ -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); +} diff --git a/buffer/src/main/java/io/netty/buffer/PoolArena.java b/buffer/src/main/java/io/netty/buffer/PoolArena.java index 778a9eee51..72d5e01cf4 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolArena.java +++ b/buffer/src/main/java/io/netty/buffer/PoolArena.java @@ -26,6 +26,7 @@ import java.util.Collections; import java.util.List; abstract class PoolArena implements PoolArenaMetric { + static final boolean HAS_UNSAFE = PlatformDependent.hasUnsafe(); enum SizeClass { Tiny, @@ -614,7 +615,8 @@ abstract class PoolArena implements PoolArenaMetric { @Override protected PooledByteBuf newByteBuf(int maxCapacity) { - return PooledHeapByteBuf.newInstance(maxCapacity); + return HAS_UNSAFE ? PooledUnsafeHeapByteBuf.newUnsafeInstance(maxCapacity) + : PooledHeapByteBuf.newInstance(maxCapacity); } @Override @@ -629,8 +631,6 @@ abstract class PoolArena implements PoolArenaMetric { static final class DirectArena extends PoolArena { - 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); } diff --git a/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java index 29c9394778..1ade6d84b0 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java @@ -25,7 +25,7 @@ import java.nio.channels.ClosedChannelException; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; -final class PooledHeapByteBuf extends PooledByteBuf { +class PooledHeapByteBuf extends PooledByteBuf { private static final Recycler RECYCLER = new Recycler() { @Override @@ -40,12 +40,12 @@ final class PooledHeapByteBuf extends PooledByteBuf { return buf; } - private PooledHeapByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) { + PooledHeapByteBuf(Recycler.Handle 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 { } @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 { } @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 { } @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 { } @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 { } @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 { } @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 { } @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 { } @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 { } @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); } diff --git a/buffer/src/main/java/io/netty/buffer/PooledUnsafeHeapByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledUnsafeHeapByteBuf.java new file mode 100644 index 0000000000..f0ffb81714 --- /dev/null +++ b/buffer/src/main/java/io/netty/buffer/PooledUnsafeHeapByteBuf.java @@ -0,0 +1,102 @@ +/* + * 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 RECYCLER = new Recycler() { + @Override + protected PooledUnsafeHeapByteBuf newObject(Handle handle) { + return new PooledUnsafeHeapByteBuf(handle, 0); + } + }; + + static PooledUnsafeHeapByteBuf newUnsafeInstance(int maxCapacity) { + PooledUnsafeHeapByteBuf buf = RECYCLER.get(); + buf.reuse(maxCapacity); + return buf; + } + + private PooledUnsafeHeapByteBuf(Handle 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 Recycler recycler() { + return RECYCLER; + } + + @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(); + } +} diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledByteBufAllocator.java b/buffer/src/main/java/io/netty/buffer/UnpooledByteBufAllocator.java index e38e40b308..1afd185373 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledByteBufAllocator.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledByteBufAllocator.java @@ -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 diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java index a854319731..a777edf8a8 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java @@ -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; /** diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeHeapByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeHeapByteBuf.java new file mode 100644 index 0000000000..9a40f61df6 --- /dev/null +++ b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeHeapByteBuf.java @@ -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(); + } +} diff --git a/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java b/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java index a38579be18..623651923a 100644 --- a/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java +++ b/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java @@ -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() { } } diff --git a/buffer/src/main/java/io/netty/buffer/UnsafeDirectSwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnsafeDirectSwappedByteBuf.java index b3d8d18ef4..206b637b5d 100644 --- a/buffer/src/main/java/io/netty/buffer/UnsafeDirectSwappedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnsafeDirectSwappedByteBuf.java @@ -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); } } diff --git a/buffer/src/main/java/io/netty/buffer/UnsafeHeapSwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnsafeHeapSwappedByteBuf.java new file mode 100644 index 0000000000..2a76906593 --- /dev/null +++ b/buffer/src/main/java/io/netty/buffer/UnsafeHeapSwappedByteBuf.java @@ -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); + } +} diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index 546e6dea1c..f728923ff5 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -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; @@ -87,6 +88,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()) { @@ -344,6 +346,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); } @@ -364,6 +382,22 @@ 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); } diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java index d6f9824417..96ffefc41d 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java @@ -39,6 +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 BYTE_ARRAY_BASE_OFFSET; /** * Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow safepoint polling @@ -106,6 +107,7 @@ final class PlatformDependent0 { UNSAFE = unsafe; if (unsafe == null) { + BYTE_ARRAY_BASE_OFFSET = -1; ADDRESS_FIELD_OFFSET = -1; UNALIGNED = false; } else { @@ -125,6 +127,7 @@ final class PlatformDependent0 { UNALIGNED = unaligned; logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED); + BYTE_ARRAY_BASE_OFFSET = arrayBaseOffset(); } } @@ -191,6 +194,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); } @@ -211,6 +230,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) {