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 eadf1bfc3f
commit 164f6f1731
12 changed files with 722 additions and 173 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; import java.util.List;
abstract class PoolArena<T> implements PoolArenaMetric { abstract class PoolArena<T> implements PoolArenaMetric {
static final boolean HAS_UNSAFE = PlatformDependent.hasUnsafe();
enum SizeClass { enum SizeClass {
Tiny, Tiny,
@ -614,7 +615,8 @@ abstract class PoolArena<T> implements PoolArenaMetric {
@Override @Override
protected PooledByteBuf<byte[]> newByteBuf(int maxCapacity) { protected PooledByteBuf<byte[]> newByteBuf(int maxCapacity) {
return PooledHeapByteBuf.newInstance(maxCapacity); return HAS_UNSAFE ? PooledUnsafeHeapByteBuf.newUnsafeInstance(maxCapacity)
: PooledHeapByteBuf.newInstance(maxCapacity);
} }
@Override @Override
@ -629,8 +631,6 @@ abstract class PoolArena<T> implements PoolArenaMetric {
static final class DirectArena extends PoolArena<ByteBuffer> { 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) { DirectArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize) {
super(parent, pageSize, maxOrder, pageShifts, 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.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; 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>() { private static final Recycler<PooledHeapByteBuf> RECYCLER = new Recycler<PooledHeapByteBuf>() {
@Override @Override
@ -40,12 +40,12 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
return buf; return buf;
} }
private PooledHeapByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) { PooledHeapByteBuf(Recycler.Handle recyclerHandle, int maxCapacity) {
super(recyclerHandle, maxCapacity); super(recyclerHandle, maxCapacity);
} }
@Override @Override
public boolean isDirect() { public final boolean isDirect() {
return false; return false;
} }
@ -91,7 +91,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @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()); checkDstIndex(index, length, dstIndex, dst.capacity());
if (dst.hasMemoryAddress()) { if (dst.hasMemoryAddress()) {
PlatformDependent.copyMemory(memory, idx(index), dst.memoryAddress() + dstIndex, length); PlatformDependent.copyMemory(memory, idx(index), dst.memoryAddress() + dstIndex, length);
@ -104,28 +104,28 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @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); checkDstIndex(index, length, dstIndex, dst.length);
System.arraycopy(memory, idx(index), dst, dstIndex, length); System.arraycopy(memory, idx(index), dst, dstIndex, length);
return this; return this;
} }
@Override @Override
public ByteBuf getBytes(int index, ByteBuffer dst) { public final ByteBuf getBytes(int index, ByteBuffer dst) {
checkIndex(index); checkIndex(index);
dst.put(memory, idx(index), Math.min(capacity() - index, dst.remaining())); dst.put(memory, idx(index), Math.min(capacity() - index, dst.remaining()));
return this; return this;
} }
@Override @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); checkIndex(index, length);
out.write(memory, idx(index), length); out.write(memory, idx(index), length);
return this; return this;
} }
@Override @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); return getBytes(index, out, length, false);
} }
@ -142,7 +142,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @Override
public int readBytes(GatheringByteChannel out, int length) throws IOException { public final int readBytes(GatheringByteChannel out, int length) throws IOException {
checkReadableBytes(length); checkReadableBytes(length);
int readBytes = getBytes(readerIndex, out, length, true); int readBytes = getBytes(readerIndex, out, length, true);
readerIndex += readBytes; readerIndex += readBytes;
@ -192,7 +192,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @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()); checkSrcIndex(index, length, srcIndex, src.capacity());
if (src.hasMemoryAddress()) { if (src.hasMemoryAddress()) {
PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, memory, idx(index), length); PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, memory, idx(index), length);
@ -205,14 +205,14 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @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); checkSrcIndex(index, length, srcIndex, src.length);
System.arraycopy(src, srcIndex, memory, idx(index), length); System.arraycopy(src, srcIndex, memory, idx(index), length);
return this; return this;
} }
@Override @Override
public ByteBuf setBytes(int index, ByteBuffer src) { public final ByteBuf setBytes(int index, ByteBuffer src) {
int length = src.remaining(); int length = src.remaining();
checkIndex(index, length); checkIndex(index, length);
src.get(memory, idx(index), length); src.get(memory, idx(index), length);
@ -220,13 +220,13 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @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); checkIndex(index, length);
return in.read(memory, idx(index), length); return in.read(memory, idx(index), length);
} }
@Override @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); checkIndex(index, length);
index = idx(index); index = idx(index);
try { try {
@ -237,7 +237,7 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @Override
public ByteBuf copy(int index, int length) { public final ByteBuf copy(int index, int length) {
checkIndex(index, length); checkIndex(index, length);
ByteBuf copy = alloc().heapBuffer(length, maxCapacity()); ByteBuf copy = alloc().heapBuffer(length, maxCapacity());
copy.writeBytes(memory, idx(index), length); copy.writeBytes(memory, idx(index), length);
@ -245,17 +245,17 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @Override
public int nioBufferCount() { public final int nioBufferCount() {
return 1; return 1;
} }
@Override @Override
public ByteBuffer[] nioBuffers(int index, int length) { public final ByteBuffer[] nioBuffers(int index, int length) {
return new ByteBuffer[] { nioBuffer(index, length) }; return new ByteBuffer[] { nioBuffer(index, length) };
} }
@Override @Override
public ByteBuffer nioBuffer(int index, int length) { public final ByteBuffer nioBuffer(int index, int length) {
checkIndex(index, length); checkIndex(index, length);
index = idx(index); index = idx(index);
ByteBuffer buf = ByteBuffer.wrap(memory, index, length); ByteBuffer buf = ByteBuffer.wrap(memory, index, length);
@ -263,40 +263,40 @@ final class PooledHeapByteBuf extends PooledByteBuf<byte[]> {
} }
@Override @Override
public ByteBuffer internalNioBuffer(int index, int length) { public final ByteBuffer internalNioBuffer(int index, int length) {
checkIndex(index, length); checkIndex(index, length);
index = idx(index); index = idx(index);
return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length); return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
} }
@Override @Override
public boolean hasArray() { public final boolean hasArray() {
return true; return true;
} }
@Override @Override
public byte[] array() { public final byte[] array() {
ensureAccessible(); ensureAccessible();
return memory; return memory;
} }
@Override @Override
public int arrayOffset() { public final int arrayOffset() {
return offset; return offset;
} }
@Override @Override
public boolean hasMemoryAddress() { public final boolean hasMemoryAddress() {
return false; return false;
} }
@Override @Override
public long memoryAddress() { public final long memoryAddress() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
protected ByteBuffer newInternalNioBuffer(byte[] memory) { protected final ByteBuffer newInternalNioBuffer(byte[] memory) {
return ByteBuffer.wrap(memory); return ByteBuffer.wrap(memory);
} }

View File

@ -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<PooledUnsafeHeapByteBuf> RECYCLER = new Recycler<PooledUnsafeHeapByteBuf>() {
@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();
}
}

View File

@ -40,7 +40,8 @@ public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
@Override @Override
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) { 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 @Override

View File

@ -32,7 +32,7 @@ import java.nio.channels.ScatteringByteChannel;
public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf { public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
private final ByteBufAllocator alloc; private final ByteBufAllocator alloc;
private byte[] array; byte[] array;
private ByteBuffer tmpNioBuf; 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 { 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(); private static final boolean UNALIGNED = PlatformDependent.isUnaligned();
static byte getByte(long address) { static byte getByte(long address) {
@ -34,14 +34,14 @@ final class UnsafeByteBufUtil {
static short getShort(long address) { static short getShort(long address) {
if (UNALIGNED) { if (UNALIGNED) {
short v = PlatformDependent.getShort(address); 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); return (short) (PlatformDependent.getByte(address) << 8 | PlatformDependent.getByte(address + 1) & 0xff);
} }
static int getUnsignedMedium(long address) { static int getUnsignedMedium(long address) {
if (UNALIGNED) { if (UNALIGNED) {
if (NATIVE_ORDER) { if (BIG_ENDIAN_NATIVE_ORDER) {
return (PlatformDependent.getByte(address) & 0xff) | return (PlatformDependent.getByte(address) & 0xff) |
(PlatformDependent.getShort(address + 1) & 0xffff) << 8; (PlatformDependent.getShort(address + 1) & 0xffff) << 8;
} }
@ -56,7 +56,7 @@ final class UnsafeByteBufUtil {
static int getInt(long address) { static int getInt(long address) {
if (UNALIGNED) { if (UNALIGNED) {
int v = PlatformDependent.getInt(address); 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 | return PlatformDependent.getByte(address) << 24 |
(PlatformDependent.getByte(address + 1) & 0xff) << 16 | (PlatformDependent.getByte(address + 1) & 0xff) << 16 |
@ -67,7 +67,7 @@ final class UnsafeByteBufUtil {
static long getLong(long address) { static long getLong(long address) {
if (UNALIGNED) { if (UNALIGNED) {
long v = PlatformDependent.getLong(address); 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 | return (long) PlatformDependent.getByte(address) << 56 |
((long) PlatformDependent.getByte(address + 1) & 0xff) << 48 | ((long) PlatformDependent.getByte(address + 1) & 0xff) << 48 |
@ -85,7 +85,8 @@ final class UnsafeByteBufUtil {
static void setShort(long address, int value) { static void setShort(long address, int value) {
if (UNALIGNED) { 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 { } else {
PlatformDependent.putByte(address, (byte) (value >>> 8)); PlatformDependent.putByte(address, (byte) (value >>> 8));
PlatformDependent.putByte(address + 1, (byte) value); PlatformDependent.putByte(address + 1, (byte) value);
@ -94,7 +95,7 @@ final class UnsafeByteBufUtil {
static void setMedium(long address, int value) { static void setMedium(long address, int value) {
if (UNALIGNED) { if (UNALIGNED) {
if (NATIVE_ORDER) { if (BIG_ENDIAN_NATIVE_ORDER) {
PlatformDependent.putByte(address, (byte) value); PlatformDependent.putByte(address, (byte) value);
PlatformDependent.putShort(address + 1, (short) (value >>> 8)); PlatformDependent.putShort(address + 1, (short) (value >>> 8));
} else { } else {
@ -110,7 +111,7 @@ final class UnsafeByteBufUtil {
static void setInt(long address, int value) { static void setInt(long address, int value) {
if (UNALIGNED) { if (UNALIGNED) {
PlatformDependent.putInt(address, NATIVE_ORDER ? value : Integer.reverseBytes(value)); PlatformDependent.putInt(address, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
} else { } else {
PlatformDependent.putByte(address, (byte) (value >>> 24)); PlatformDependent.putByte(address, (byte) (value >>> 24));
PlatformDependent.putByte(address + 1, (byte) (value >>> 16)); PlatformDependent.putByte(address + 1, (byte) (value >>> 16));
@ -121,7 +122,7 @@ final class UnsafeByteBufUtil {
static void setLong(long address, long value) { static void setLong(long address, long value) {
if (UNALIGNED) { if (UNALIGNED) {
PlatformDependent.putLong(address, NATIVE_ORDER ? value : Long.reverseBytes(value)); PlatformDependent.putLong(address, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
} else { } else {
PlatformDependent.putByte(address, (byte) (value >>> 56)); PlatformDependent.putByte(address, (byte) (value >>> 56));
PlatformDependent.putByte(address + 1, (byte) (value >>> 48)); 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() { } private UnsafeByteBufUtil() { }
} }

View File

@ -18,24 +18,16 @@ package io.netty.buffer;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
import java.nio.ByteOrder;
/** /**
* Special {@link SwappedByteBuf} for {@link ByteBuf}s that are backed by a {@code memoryAddress}. * Special {@link SwappedByteBuf} for {@link ByteBuf}s that are backed by a {@code memoryAddress}.
*/ */
final class UnsafeDirectSwappedByteBuf extends SwappedByteBuf { final class UnsafeDirectSwappedByteBuf extends AbstractUnsafeSwappedByteBuf {
private static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
private final boolean nativeByteOrder;
private final AbstractByteBuf wrapped;
UnsafeDirectSwappedByteBuf(AbstractByteBuf buf) { UnsafeDirectSwappedByteBuf(AbstractByteBuf buf) {
super(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. // We need to call wrapped.memoryAddress() everytime and NOT cache it as it may change if the buffer expand.
// See: // See:
// - https://github.com/netty/netty/issues/2587 // - https://github.com/netty/netty/issues/2587
@ -44,144 +36,32 @@ final class UnsafeDirectSwappedByteBuf extends SwappedByteBuf {
} }
@Override @Override
public long getLong(int index) { protected long _getLong(AbstractByteBuf wrapped, int index) {
wrapped.checkIndex(index, 8); return PlatformDependent.getLong(addr(wrapped, index));
long v = PlatformDependent.getLong(addr(index));
return nativeByteOrder? v : Long.reverseBytes(v);
} }
@Override @Override
public float getFloat(int index) { protected int _getInt(AbstractByteBuf wrapped, int index) {
return Float.intBitsToFloat(getInt(index)); return PlatformDependent.getInt(addr(wrapped, index));
} }
@Override @Override
public double getDouble(int index) { protected short _getShort(AbstractByteBuf wrapped, int index) {
return Double.longBitsToDouble(getLong(index)); return PlatformDependent.getShort(addr(wrapped, index));
} }
@Override @Override
public char getChar(int index) { protected void _setShort(AbstractByteBuf wrapped, int index, short value) {
return (char) getShort(index); PlatformDependent.putShort(addr(wrapped, index), value);
} }
@Override @Override
public long getUnsignedInt(int index) { protected void _setInt(AbstractByteBuf wrapped, int index, int value) {
return getInt(index) & 0xFFFFFFFFL; PlatformDependent.putInt(addr(wrapped, index), value);
} }
@Override @Override
public int getInt(int index) { protected void _setLong(AbstractByteBuf wrapped, int index, long value) {
wrapped.checkIndex(index, 4); PlatformDependent.putLong(addr(wrapped, index), value);
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));
} }
} }

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.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -87,6 +88,7 @@ public final class PlatformDependent {
private static final int BIT_MODE = bitMode0(); private static final int BIT_MODE = bitMode0();
private static final int ADDRESS_SIZE = addressSize0(); private static final int ADDRESS_SIZE = addressSize0();
private static final boolean NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
static { static {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@ -344,6 +346,22 @@ public final class PlatformDependent {
return PlatformDependent0.getLong(address); 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) { public static void putOrderedObject(Object object, long address, Object value) {
PlatformDependent0.putOrderedObject(object, address, value); PlatformDependent0.putOrderedObject(object, address, value);
} }
@ -364,6 +382,22 @@ public final class PlatformDependent {
PlatformDependent0.putLong(address, value); 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) { public static void copyMemory(long srcAddr, long dstAddr, long length) {
PlatformDependent0.copyMemory(srcAddr, dstAddr, length); PlatformDependent0.copyMemory(srcAddr, dstAddr, length);
} }

View File

@ -39,6 +39,7 @@ final class PlatformDependent0 {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class); private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
static final Unsafe UNSAFE; static final Unsafe UNSAFE;
private static final long ADDRESS_FIELD_OFFSET; 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 * 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; UNSAFE = unsafe;
if (unsafe == null) { if (unsafe == null) {
BYTE_ARRAY_BASE_OFFSET = -1;
ADDRESS_FIELD_OFFSET = -1; ADDRESS_FIELD_OFFSET = -1;
UNALIGNED = false; UNALIGNED = false;
} else { } else {
@ -125,6 +127,7 @@ final class PlatformDependent0 {
UNALIGNED = unaligned; UNALIGNED = unaligned;
logger.debug("java.nio.Bits.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); 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) { static void putOrderedObject(Object object, long address, Object value) {
UNSAFE.putOrderedObject(object, address, value); UNSAFE.putOrderedObject(object, address, value);
} }
@ -211,6 +230,22 @@ final class PlatformDependent0 {
UNSAFE.putLong(address, value); 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) { static void copyMemory(long srcAddr, long dstAddr, long length) {
//UNSAFE.copyMemory(srcAddr, dstAddr, length); //UNSAFE.copyMemory(srcAddr, dstAddr, length);
while (length > 0) { while (length > 0) {