From 88df53ec1a53912c2e34892247c8218c2fa01838 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Wed, 6 Mar 2013 18:22:16 +0900 Subject: [PATCH] Fix infinite recursion when transferring data between different type of buffers / Add ByteBuf.hasMemoryAddress/memoryAddress() - Fixes: #1109 and #1110 --- .../java/io/netty/buffer/AbstractByteBuf.java | 25 +-- .../main/java/io/netty/buffer/ByteBuf.java | 14 ++ .../netty/buffer/DefaultCompositeByteBuf.java | 144 +++++------------- .../io/netty/buffer/DuplicatedByteBuf.java | 10 ++ .../java/io/netty/buffer/EmptyByteBuf.java | 23 +++ .../io/netty/buffer/PooledDirectByteBuf.java | 48 +++--- .../io/netty/buffer/PooledHeapByteBuf.java | 28 +++- .../buffer/PooledUnsafeDirectByteBuf.java | 46 ++++-- .../java/io/netty/buffer/ReadOnlyByteBuf.java | 10 ++ .../java/io/netty/buffer/SlicedByteBuf.java | 22 ++- .../java/io/netty/buffer/SwappedByteBuf.java | 10 ++ .../netty/buffer/UnpooledDirectByteBuf.java | 45 +++--- .../io/netty/buffer/UnpooledHeapByteBuf.java | 28 +++- .../buffer/UnpooledUnsafeDirectByteBuf.java | 55 +++++-- .../PooledBigEndianDirectByteBufTest.java | 41 +++++ .../PooledBigEndianHeapByteBufTest.java | 38 +++++ .../PooledLittleEndianDirectByteBufTest.java | 41 +++++ .../PooledLittleEndianHeapByteBufTest.java | 40 +++++ .../handler/codec/ReplayingDecoderBuffer.java | 10 ++ 19 files changed, 486 insertions(+), 192 deletions(-) create mode 100644 buffer/src/test/java/io/netty/buffer/PooledBigEndianDirectByteBufTest.java create mode 100644 buffer/src/test/java/io/netty/buffer/PooledBigEndianHeapByteBufTest.java create mode 100644 buffer/src/test/java/io/netty/buffer/PooledLittleEndianDirectByteBufTest.java create mode 100644 buffer/src/test/java/io/netty/buffer/PooledLittleEndianHeapByteBufTest.java diff --git a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java index 63241ddd00..ab88eb780e 100644 --- a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java @@ -440,15 +440,6 @@ public abstract class AbstractByteBuf implements ByteBuf { @Override public ByteBuf getBytes(int index, ByteBuf dst, int length) { - checkIndex(index, length); - if (dst == null) { - throw new NullPointerException("dst"); - } - - if (length > dst.writableBytes()) { - throw new IndexOutOfBoundsException(String.format( - "length(%d) exceeds dst.writableBytes(%d) where dst is: %s", length, dst.writableBytes(), dst)); - } getBytes(index, dst, dst.writerIndex(), length); dst.writerIndex(dst.writerIndex() + length); return this; @@ -1102,6 +1093,22 @@ public abstract class AbstractByteBuf implements ByteBuf { } } + protected final void checkSrcIndex(int index, int length, int srcIndex, int srcCapacity) { + checkIndex(index, length); + if (srcIndex < 0 || srcIndex > srcCapacity - length) { + throw new IndexOutOfBoundsException(String.format( + "srcIndex: %d, length: %d (expected: range(0, %d))", srcIndex, length, srcCapacity)); + } + } + + protected final void checkDstIndex(int index, int length, int dstIndex, int dstCapacity) { + checkIndex(index, length); + if (dstIndex < 0 || dstIndex > dstCapacity - length) { + throw new IndexOutOfBoundsException(String.format( + "dstIndex: %d, length: %d (expected: range(0, %d))", dstIndex, length, dstCapacity)); + } + } + /** * Throws an {@link IndexOutOfBoundsException} if the current * {@linkplain #readableBytes() readable bytes} of this buffer is less diff --git a/buffer/src/main/java/io/netty/buffer/ByteBuf.java b/buffer/src/main/java/io/netty/buffer/ByteBuf.java index 39c2d21772..8cd6d4562e 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBuf.java @@ -1835,6 +1835,20 @@ public interface ByteBuf extends Buf, Comparable { */ int arrayOffset(); + /** + * Returns {@code true} if and only if this buffer has a reference to the low-level memory address that points + * to the backing data. + */ + boolean hasMemoryAddress(); + + /** + * Returns the low-level memory address that point to the first byte of ths backing data. + * + * @throws UnsupportedOperationException + * if this buffer does not support accessing the low-level memory address + */ + long memoryAddress(); + /** * Decodes this buffer's readable bytes into a string with the specified * character set name. This method is identical to diff --git a/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java b/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java index 5cacc49a5c..7604c588be 100644 --- a/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/DefaultCompositeByteBuf.java @@ -351,15 +351,11 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public List decompose(int offset, int length) { + checkIndex(offset, length); if (length == 0) { return Collections.emptyList(); } - if (offset + length > capacity()) { - throw new IndexOutOfBoundsException("Too many bytes to decompose - Need " - + (offset + length) + ", capacity is " + capacity()); - } - int componentId = toComponentIndex(offset); List slice = new ArrayList(components.size()); @@ -428,6 +424,22 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf throw new UnsupportedOperationException(); } + @Override + public boolean hasMemoryAddress() { + if (components.size() == 1) { + return components.get(0).buf.hasMemoryAddress(); + } + return false; + } + + @Override + public long memoryAddress() { + if (components.size() == 1) { + return components.get(0).buf.memoryAddress(); + } + throw new UnsupportedOperationException(); + } + @Override public int capacity() { if (components.isEmpty()) { @@ -510,10 +522,7 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public int toComponentIndex(int offset) { assert !freed; - if (offset < 0 || offset >= capacity()) { - throw new IndexOutOfBoundsException(String.format( - "offset: %d (expected: >= 0 && < capacity(%d))", offset, capacity())); - } + checkIndex(offset); Component c = lastAccessed; if (c == null) { @@ -615,19 +624,12 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public CompositeByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - if (index > capacity() - length || dstIndex > dst.length - length) { - throw new IndexOutOfBoundsException("Too many bytes to read - Needs " - + (index + length) + ", maximum is " + capacity() + " or " - + dst.length); - } - if (index < 0) { - throw new IndexOutOfBoundsException("index must be >= 0"); - } + checkDstIndex(index, length, dstIndex, dst.length); if (length == 0) { return this; } - int i = toComponentIndex(index); + int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; @@ -647,16 +649,11 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf int limit = dst.limit(); int length = dst.remaining(); - if (index > capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " - + (index + length) + ", maximum is " + capacity()); - } - if (index < 0) { - throw new IndexOutOfBoundsException("index must be >= 0"); - } + checkIndex(index, length); if (length == 0) { return this; } + int i = toComponentIndex(index); try { while (length > 0) { @@ -678,17 +675,7 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public CompositeByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - if (index > capacity() - length || dstIndex > dst.capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " - + (index + length) + " or " + (dstIndex + length) + ", maximum is " - + capacity() + " or " + dst.capacity()); - } - if (index < 0) { - throw new IndexOutOfBoundsException("index must be >= 0"); - } - if (length == 0) { - return this; - } + checkDstIndex(index, length, dstIndex, dst.capacity()); int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); @@ -722,15 +709,8 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf } @Override - public CompositeByteBuf getBytes(int index, OutputStream out, int length) - throws IOException { - if (index > capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to be read - needs " - + (index + length) + ", maximum of " + capacity()); - } - if (index < 0) { - throw new IndexOutOfBoundsException("index must be >= 0"); - } + public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws IOException { + checkIndex(index, length); if (length == 0) { return this; } @@ -839,14 +819,9 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public CompositeByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { - int componentId = toComponentIndex(index); - if (index > capacity() - length || srcIndex > src.length - length) { - throw new IndexOutOfBoundsException("Too many bytes to read - needs " - + (index + length) + " or " + (srcIndex + length) + ", maximum is " - + capacity() + " or " + src.length); - } + checkSrcIndex(index, length, srcIndex, src.length); - int i = componentId; + int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; @@ -863,15 +838,11 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public CompositeByteBuf setBytes(int index, ByteBuffer src) { - int componentId = toComponentIndex(index); int limit = src.limit(); int length = src.remaining(); - if (index > capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to be written - Needs " - + (index + length) + ", maximum is " + capacity()); - } - int i = componentId; + checkIndex(index, length); + int i = toComponentIndex(index); try { while (length > 0) { Component c = components.get(i); @@ -892,14 +863,9 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public CompositeByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - int componentId = toComponentIndex(index); - if (index > capacity() - length || srcIndex > src.capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to be written - Needs " - + (index + length) + " or " + (srcIndex + length) + ", maximum is " - + capacity() + " or " + src.capacity()); - } + checkSrcIndex(index, length, srcIndex, src.capacity()); - int i = componentId; + int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; @@ -915,15 +881,10 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf } @Override - public int setBytes(int index, InputStream in, int length) - throws IOException { - int componentId = toComponentIndex(index); - if (index > capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to write - Needs " - + (index + length) + ", maximum is " + capacity()); - } + public int setBytes(int index, InputStream in, int length) throws IOException { + checkIndex(index, length); - int i = componentId; + int i = toComponentIndex(index); int readBytes = 0; do { @@ -956,15 +917,10 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf } @Override - public int setBytes(int index, ScatteringByteChannel in, int length) - throws IOException { - int componentId = toComponentIndex(index); - if (index > capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to write - Needs " - + (index + length) + ", maximum is " + capacity()); - } + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { + checkIndex(index, length); - int i = componentId; + int i = toComponentIndex(index); int readBytes = 0; do { Component c = components.get(i); @@ -1002,14 +958,9 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public ByteBuf copy(int index, int length) { - int componentId = toComponentIndex(index); - if (index > capacity() - length) { - throw new IndexOutOfBoundsException("Too many bytes to copy - Needs " - + (index + length) + ", maximum is " + capacity()); - } - + checkIndex(index, length); ByteBuf dst = Unpooled.buffer(length); - copyTo(index, length, componentId, dst); + copyTo(index, length, toComponentIndex(index), dst); return dst; } @@ -1045,10 +996,7 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf private Component findComponent(int offset) { assert !freed; - if (offset < 0 || offset >= capacity()) { - throw new IndexOutOfBoundsException(String.format( - "offset: %d (expected: >= 0 && < capacity(%d))", offset, capacity())); - } + checkIndex(offset); Component c = lastAccessed; if (c == null) { @@ -1114,21 +1062,13 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf @Override public ByteBuffer[] nioBuffers(int index, int length) { - if (index + length > capacity()) { - throw new IndexOutOfBoundsException("Too many bytes to convert - Needs" - + (index + length) + ", maximum is " + capacity()); - } - if (index < 0) { - throw new IndexOutOfBoundsException("index must be >= 0"); - } + checkIndex(index, length); if (length == 0) { return EMPTY_NIOBUFFERS; } - int componentId = toComponentIndex(index); List buffers = new ArrayList(components.size()); - - int i = componentId; + int i = toComponentIndex(index); while (length > 0) { Component c = components.get(i); ByteBuf s = c.buf; diff --git a/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java b/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java index 3fc3d74d3c..93004943ce 100644 --- a/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/DuplicatedByteBuf.java @@ -91,6 +91,16 @@ public class DuplicatedByteBuf extends AbstractDerivedByteBuf { return buffer.arrayOffset(); } + @Override + public boolean hasMemoryAddress() { + return buffer.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return buffer.memoryAddress(); + } + @Override public byte getByte(int index) { return _getByte(index); diff --git a/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java b/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java index 181c0b1d6a..c6b93d1041 100644 --- a/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/EmptyByteBuf.java @@ -16,6 +16,8 @@ package io.netty.buffer; +import io.netty.util.internal.PlatformDependent; + import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -34,6 +36,7 @@ public final class EmptyByteBuf implements ByteBuf { private final ByteOrder order; private final ByteBuffer nioBuf = ByteBuffer.allocateDirect(0); + private final long memoryAddress; private final byte[] array = EMPTY_ARRAY; private final String str; @@ -41,6 +44,12 @@ public final class EmptyByteBuf implements ByteBuf { this.order = order; nioBuf.order(order); str = getClass().getSimpleName() + (order == ByteOrder.BIG_ENDIAN? "BE" : "LE"); + + if (PlatformDependent.hasUnsafe()) { + memoryAddress = PlatformDependent.directBufferAddress(nioBuf); + } else { + memoryAddress = -1; + } } @Override @@ -745,6 +754,20 @@ public final class EmptyByteBuf implements ByteBuf { return 0; } + @Override + public boolean hasMemoryAddress() { + return memoryAddress != -1; + } + + @Override + public long memoryAddress() { + if (hasMemoryAddress()) { + return memoryAddress; + } else { + throw new UnsupportedOperationException(); + } + } + @Override public String toString(Charset charset) { return ""; diff --git a/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java index 871a9676b6..588b593535 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java @@ -68,15 +68,15 @@ final class PooledDirectByteBuf extends PooledByteBuf { @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - checkIndex(index, length); - if (dst instanceof PooledDirectByteBuf) { - PooledDirectByteBuf bbdst = (PooledDirectByteBuf) dst; - ByteBuffer data = bbdst.internalNioBuffer(); - dstIndex = bbdst.idx(dstIndex); - data.clear().position(dstIndex).limit(dstIndex + length); - getBytes(index, data); - } else if (dst.hasArray()) { + checkDstIndex(index, length, dstIndex, dst.capacity()); + if (dst.hasArray()) { getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length); + } else if (dst.nioBufferCount() > 0) { + for (ByteBuffer bb: dst.nioBuffers(dstIndex, length)) { + int bbLen = bb.remaining(); + getBytes(index, bb); + index += bbLen; + } } else { dst.setBytes(dstIndex, this, index, length); } @@ -85,7 +85,7 @@ final class PooledDirectByteBuf extends PooledByteBuf { @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - checkIndex(index, length); + checkDstIndex(index, length, dstIndex, dst.length); ByteBuffer tmpBuf = internalNioBuffer(); index = idx(index); tmpBuf.clear().position(index).limit(index + length); @@ -162,15 +162,15 @@ final class PooledDirectByteBuf extends PooledByteBuf { @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - checkIndex(index, length); - if (src instanceof PooledDirectByteBuf) { - PooledDirectByteBuf bbsrc = (PooledDirectByteBuf) src; - ByteBuffer data = bbsrc.internalNioBuffer(); - srcIndex = bbsrc.idx(srcIndex); - data.clear().position(srcIndex).limit(srcIndex + length); - setBytes(index, data); - } else if (src.hasArray()) { + checkSrcIndex(index, length, srcIndex, src.capacity()); + if (src.hasArray()) { setBytes(index, src.array(), src.arrayOffset() + srcIndex, length); + } else if (src.nioBufferCount() > 0) { + for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) { + int bbLen = bb.remaining(); + setBytes(index, bb); + index += bbLen; + } } else { src.getBytes(srcIndex, this, index, length); } @@ -179,7 +179,7 @@ final class PooledDirectByteBuf extends PooledByteBuf { @Override public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { - checkIndex(index, length); + checkSrcIndex(index, length, srcIndex, src.length); ByteBuffer tmpBuf = internalNioBuffer(); index = idx(index); tmpBuf.clear().position(index).limit(index + length); @@ -231,7 +231,7 @@ final class PooledDirectByteBuf extends PooledByteBuf { @Override public ByteBuf copy(int index, int length) { checkIndex(index, length); - ByteBuf copy = alloc().directBuffer(capacity(), maxCapacity()); + ByteBuf copy = alloc().directBuffer(length, maxCapacity()); copy.writeBytes(this, index, length); return copy; } @@ -267,4 +267,14 @@ final class PooledDirectByteBuf extends PooledByteBuf { public int arrayOffset() { throw new UnsupportedOperationException("direct buffer"); } + + @Override + public boolean hasMemoryAddress() { + return false; + } + + @Override + public long memoryAddress() { + throw new UnsupportedOperationException(); + } } diff --git a/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java index 90fc197681..a03c8f98c1 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledHeapByteBuf.java @@ -14,6 +14,8 @@ package io.netty.buffer; +import io.netty.util.internal.PlatformDependent; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -76,10 +78,12 @@ final class PooledHeapByteBuf extends PooledByteBuf { @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - if (dst.hasArray()) { + checkDstIndex(index, length, dstIndex, dst.capacity()); + if (dst.hasMemoryAddress()) { + PlatformDependent.copyMemory(memory, idx(index), dst.memoryAddress() + dstIndex, length); + } if (dst.hasArray()) { getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length); } else { - checkIndex(index, length); dst.setBytes(dstIndex, memory, idx(index), length); } return this; @@ -87,7 +91,7 @@ final class PooledHeapByteBuf extends PooledByteBuf { @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - checkIndex(index, length); + checkDstIndex(index, length, dstIndex, dst.length); System.arraycopy(memory, idx(index), dst, dstIndex, length); return this; } @@ -157,8 +161,10 @@ final class PooledHeapByteBuf extends PooledByteBuf { @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - checkIndex(index, length); - if (src.hasArray()) { + checkSrcIndex(index, length, srcIndex, src.capacity()); + if (src.hasMemoryAddress()) { + PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, memory, idx(index), length); + } else if (src.hasArray()) { setBytes(index, src.array(), src.arrayOffset() + srcIndex, length); } else { src.getBytes(srcIndex, memory, idx(index), length); @@ -168,7 +174,7 @@ final class PooledHeapByteBuf extends PooledByteBuf { @Override public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { - checkIndex(index, length); + checkSrcIndex(index, length, srcIndex, src.length); System.arraycopy(src, srcIndex, memory, idx(index), length); return this; } @@ -238,6 +244,16 @@ final class PooledHeapByteBuf extends PooledByteBuf { return offset; } + @Override + public boolean hasMemoryAddress() { + return false; + } + + @Override + public long memoryAddress() { + throw new UnsupportedOperationException(); + } + @Override protected ByteBuffer newInternalNioBuffer(byte[] memory) { return ByteBuffer.wrap(memory); diff --git a/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java index 406f889652..b1240472bb 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java @@ -96,10 +96,16 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf { @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { checkIndex(index, length); + if (dst == null) { + throw new NullPointerException("dst"); + } + if (dstIndex < 0 || dstIndex > dst.capacity() - length) { + throw new IndexOutOfBoundsException("dstIndex: " + dstIndex); + } + if (length != 0) { - if (dst instanceof PooledUnsafeDirectByteBuf) { - PooledUnsafeDirectByteBuf bbdst = (PooledUnsafeDirectByteBuf) dst; - PlatformDependent.copyMemory(addr(index), bbdst.addr(dstIndex), length); + if (dst.hasMemoryAddress()) { + PlatformDependent.copyMemory(addr(index), dst.memoryAddress() + dstIndex, length); } else if (dst.hasArray()) { PlatformDependent.copyMemory(addr(index), dst.array(), dst.arrayOffset() + dstIndex, length); } else { @@ -112,6 +118,12 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf { @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { checkIndex(index, length); + if (dst == null) { + throw new NullPointerException("dst"); + } + if (dstIndex < 0 || dstIndex > dst.length - length) { + throw new IndexOutOfBoundsException("dstIndex: " + dstIndex); + } if (length != 0) { PlatformDependent.copyMemory(addr(index), dst, dstIndex, length); } @@ -184,10 +196,16 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf { @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { checkIndex(index, length); + if (src == null) { + throw new NullPointerException("src"); + } + if (srcIndex < 0 || srcIndex > src.capacity() - length) { + throw new IndexOutOfBoundsException("srcIndex: " + srcIndex); + } + if (length != 0) { - if (src instanceof PooledUnsafeDirectByteBuf) { - PooledUnsafeDirectByteBuf bbsrc = (PooledUnsafeDirectByteBuf) src; - PlatformDependent.copyMemory(bbsrc.addr(srcIndex), addr(index), length); + if (src.hasMemoryAddress()) { + PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, addr(index), length); } else if (src.hasArray()) { PlatformDependent.copyMemory(src.array(), src.arrayOffset() + srcIndex, addr(index), length); } else { @@ -247,10 +265,10 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf { @Override public ByteBuf copy(int index, int length) { checkIndex(index, length); - PooledUnsafeDirectByteBuf copy = (PooledUnsafeDirectByteBuf) alloc().directBuffer(capacity(), maxCapacity()); + PooledUnsafeDirectByteBuf copy = (PooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity()); if (length != 0) { - PlatformDependent.copyMemory(addr(index), copy.addr(index), length); - copy.setIndex(index, index + length); + PlatformDependent.copyMemory(addr(index), copy.addr(0), length); + copy.setIndex(0, length); } return copy; } @@ -287,6 +305,16 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf { throw new UnsupportedOperationException("direct buffer"); } + @Override + public boolean hasMemoryAddress() { + return true; + } + + @Override + public long memoryAddress() { + return memoryAddress; + } + private long addr(int index) { return memoryAddress + index; } diff --git a/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java b/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java index df6e912b53..20549be5c3 100644 --- a/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/ReadOnlyByteBuf.java @@ -79,6 +79,16 @@ public class ReadOnlyByteBuf extends AbstractDerivedByteBuf { throw new ReadOnlyBufferException(); } + @Override + public boolean hasMemoryAddress() { + return false; + } + + @Override + public long memoryAddress() { + throw new ReadOnlyBufferException(); + } + @Override public ByteBuf discardReadBytes() { throw new ReadOnlyBufferException(); diff --git a/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java b/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java index c3bae62db2..e0ed1d0620 100644 --- a/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/SlicedByteBuf.java @@ -102,6 +102,16 @@ public class SlicedByteBuf extends AbstractDerivedByteBuf { return buffer.arrayOffset() + adjustment; } + @Override + public boolean hasMemoryAddress() { + return buffer.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return buffer.memoryAddress() + adjustment; + } + @Override protected byte _getByte(int index) { return buffer.getByte(index + adjustment); @@ -217,30 +227,26 @@ public class SlicedByteBuf extends AbstractDerivedByteBuf { } @Override - public ByteBuf getBytes(int index, OutputStream out, int length) - throws IOException { + public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { checkIndex(index, length); buffer.getBytes(index + adjustment, out, length); return this; } @Override - public int getBytes(int index, GatheringByteChannel out, int length) - throws IOException { + public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { checkIndex(index, length); return buffer.getBytes(index + adjustment, out, length); } @Override - public int setBytes(int index, InputStream in, int length) - throws IOException { + public int setBytes(int index, InputStream in, int length) throws IOException { checkIndex(index, length); return buffer.setBytes(index + adjustment, in, length); } @Override - public int setBytes(int index, ScatteringByteChannel in, int length) - throws IOException { + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { checkIndex(index, length); return buffer.setBytes(index + adjustment, in, length); } diff --git a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java index 220f8130dc..a18c4dc1e4 100644 --- a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java @@ -793,6 +793,16 @@ public final class SwappedByteBuf implements ByteBuf { return buf.arrayOffset(); } + @Override + public boolean hasMemoryAddress() { + return buf.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return buf.memoryAddress(); + } + @Override public String toString(Charset charset) { return buf.toString(charset); diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java index 76398db035..8511730a1f 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java @@ -195,6 +195,16 @@ final class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { throw new UnsupportedOperationException("direct buffer"); } + @Override + public boolean hasMemoryAddress() { + return false; + } + + @Override + public long memoryAddress() { + throw new UnsupportedOperationException(); + } + @Override public byte getByte(int index) { ensureAccessible(); @@ -252,14 +262,15 @@ final class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - ensureAccessible(); - if (dst instanceof UnpooledDirectByteBuf) { - UnpooledDirectByteBuf bbdst = (UnpooledDirectByteBuf) dst; - ByteBuffer data = bbdst.internalNioBuffer(); - data.clear().position(dstIndex).limit(dstIndex + length); - getBytes(index, data); - } else if (dst.hasArray()) { + checkDstIndex(index, length, dstIndex, dst.capacity()); + if (dst.hasArray()) { getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length); + } else if (dst.nioBufferCount() > 0) { + for (ByteBuffer bb: dst.nioBuffers(dstIndex, length)) { + int bbLen = bb.remaining(); + getBytes(index, bb); + index += bbLen; + } } else { dst.setBytes(dstIndex, this, index, length); } @@ -268,7 +279,7 @@ final class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - checkIndex(index, length); + checkDstIndex(index, length, dstIndex, dst.length); if (dst == null) { throw new NullPointerException("dst"); } @@ -361,15 +372,15 @@ final class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - ensureAccessible(); - if (src instanceof UnpooledDirectByteBuf) { - UnpooledDirectByteBuf bbsrc = (UnpooledDirectByteBuf) src; - ByteBuffer data = bbsrc.internalNioBuffer(); - - data.clear().position(srcIndex).limit(srcIndex + length); - setBytes(index, data); - } else if (buffer.hasArray()) { + checkSrcIndex(index, length, srcIndex, src.capacity()); + if (buffer.hasArray()) { src.getBytes(srcIndex, buffer.array(), index + buffer.arrayOffset(), length); + } else if (src.nioBufferCount() > 0) { + for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) { + int bbLen = bb.remaining(); + setBytes(index, bb); + index += bbLen; + } } else { src.getBytes(srcIndex, this, index, length); } @@ -378,7 +389,7 @@ final class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf { @Override public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { - ensureAccessible(); + checkSrcIndex(index, length, srcIndex, src.length); ByteBuffer tmpBuf = internalNioBuffer(); tmpBuf.clear().position(index).limit(index + length); tmpBuf.put(src, srcIndex, length); diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java index 92cb25afac..21a61964ca 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledHeapByteBuf.java @@ -15,6 +15,8 @@ */ package io.netty.buffer; +import io.netty.util.internal.PlatformDependent; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -145,10 +147,22 @@ final class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf { return 0; } + @Override + public boolean hasMemoryAddress() { + return false; + } + + @Override + public long memoryAddress() { + throw new UnsupportedOperationException(); + } + @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - ensureAccessible(); - if (dst.hasArray()) { + checkDstIndex(index, length, dstIndex, dst.capacity()); + if (dst.hasMemoryAddress()) { + PlatformDependent.copyMemory(array, index, dst.memoryAddress() + dstIndex, length); + } else if (dst.hasArray()) { getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length); } else { dst.setBytes(dstIndex, array, index, length); @@ -158,7 +172,7 @@ final class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf { @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { - ensureAccessible(); + checkDstIndex(index, length, dstIndex, dst.length); System.arraycopy(array, index, dst, dstIndex, length); return this; } @@ -185,8 +199,10 @@ final class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf { @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - ensureAccessible(); - if (src.hasArray()) { + checkSrcIndex(index, length, srcIndex, src.capacity()); + if (src.hasMemoryAddress()) { + PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, array, index, length); + } else if (src.hasArray()) { setBytes(index, src.array(), src.arrayOffset() + srcIndex, length); } else { src.getBytes(srcIndex, array, index, length); @@ -196,7 +212,7 @@ final class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf { @Override public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { - ensureAccessible(); + checkSrcIndex(index, length, srcIndex, src.length); System.arraycopy(src, srcIndex, array, index, length); return this; } diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java index cc16f10782..a0510dbf20 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java @@ -199,6 +199,16 @@ final class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf throw new UnsupportedOperationException("direct buffer"); } + @Override + public boolean hasMemoryAddress() { + return true; + } + + @Override + public long memoryAddress() { + return memoryAddress; + } + @Override protected byte _getByte(int index) { return PlatformDependent.getByte(addr(index)); @@ -232,10 +242,16 @@ final class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { - ensureAccessible(); - if (dst instanceof UnpooledUnsafeDirectByteBuf) { - UnpooledUnsafeDirectByteBuf bbdst = (UnpooledUnsafeDirectByteBuf) dst; - PlatformDependent.copyMemory(addr(index), bbdst.addr(dstIndex), length); + checkIndex(index, length); + if (dst == null) { + throw new NullPointerException("dst"); + } + if (dstIndex < 0 || dstIndex > dst.capacity() - length) { + throw new IndexOutOfBoundsException("dstIndex: " + dstIndex); + } + + if (dst.hasMemoryAddress()) { + PlatformDependent.copyMemory(addr(index), dst.memoryAddress() + dstIndex, length); } else if (dst.hasArray()) { PlatformDependent.copyMemory(addr(index), dst.array(), dst.arrayOffset() + dstIndex, length); } else { @@ -305,14 +321,22 @@ final class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { - ensureAccessible(); - if (src instanceof UnpooledUnsafeDirectByteBuf) { - UnpooledUnsafeDirectByteBuf bbsrc = (UnpooledUnsafeDirectByteBuf) src; - PlatformDependent.copyMemory(bbsrc.addr(srcIndex), addr(index), length); - } else if (buffer.hasArray()) { - PlatformDependent.copyMemory(src.array(), src.arrayOffset() + srcIndex, addr(index), length); - } else { - src.getBytes(srcIndex, this, index, length); + checkIndex(index, length); + if (src == null) { + throw new NullPointerException("src"); + } + if (srcIndex < 0 || srcIndex > src.capacity() - length) { + throw new IndexOutOfBoundsException("srcIndex: " + srcIndex); + } + + if (length != 0) { + if (src.hasMemoryAddress()) { + PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, addr(index), length); + } else if (buffer.hasArray()) { + PlatformDependent.copyMemory(src.array(), src.arrayOffset() + srcIndex, addr(index), length); + } else { + src.getBytes(srcIndex, this, index, length); + } } return this; } @@ -408,11 +432,10 @@ final class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf @Override public ByteBuf copy(int index, int length) { checkIndex(index, length); - UnpooledUnsafeDirectByteBuf copy = - (UnpooledUnsafeDirectByteBuf) alloc().directBuffer(capacity(), maxCapacity()); + UnpooledUnsafeDirectByteBuf copy = (UnpooledUnsafeDirectByteBuf) alloc().directBuffer(length, maxCapacity()); if (length != 0) { - PlatformDependent.copyMemory(addr(index), copy.addr(index), length); - copy.setIndex(index, index + length); + PlatformDependent.copyMemory(addr(index), copy.addr(0), length); + copy.setIndex(0, length); } return copy; } diff --git a/buffer/src/test/java/io/netty/buffer/PooledBigEndianDirectByteBufTest.java b/buffer/src/test/java/io/netty/buffer/PooledBigEndianDirectByteBufTest.java new file mode 100644 index 0000000000..06f898bf78 --- /dev/null +++ b/buffer/src/test/java/io/netty/buffer/PooledBigEndianDirectByteBufTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012 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 java.nio.ByteOrder; + +import static org.junit.Assert.*; + +/** + * Tests big-endian direct channel buffers + */ +public class PooledBigEndianDirectByteBufTest extends AbstractByteBufTest { + + private ByteBuf buffer; + + @Override + protected ByteBuf newBuffer(int length) { + buffer = PooledByteBufAllocator.DEFAULT.directBuffer(length); + assertSame(ByteOrder.BIG_ENDIAN, buffer.order()); + assertEquals(0, buffer.writerIndex()); + return buffer; + } + + @Override + protected ByteBuf[] components() { + return new ByteBuf[] { buffer }; + } +} diff --git a/buffer/src/test/java/io/netty/buffer/PooledBigEndianHeapByteBufTest.java b/buffer/src/test/java/io/netty/buffer/PooledBigEndianHeapByteBufTest.java new file mode 100644 index 0000000000..46cf2feb6f --- /dev/null +++ b/buffer/src/test/java/io/netty/buffer/PooledBigEndianHeapByteBufTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012 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 static org.junit.Assert.*; + +/** + * Tests big-endian heap channel buffers + */ +public class PooledBigEndianHeapByteBufTest extends AbstractByteBufTest { + + private ByteBuf buffer; + + @Override + protected ByteBuf newBuffer(int length) { + buffer = PooledByteBufAllocator.DEFAULT.heapBuffer(length); + assertEquals(0, buffer.writerIndex()); + return buffer; + } + + @Override + protected ByteBuf[] components() { + return new ByteBuf[] { buffer }; + } +} diff --git a/buffer/src/test/java/io/netty/buffer/PooledLittleEndianDirectByteBufTest.java b/buffer/src/test/java/io/netty/buffer/PooledLittleEndianDirectByteBufTest.java new file mode 100644 index 0000000000..bf8579b3cb --- /dev/null +++ b/buffer/src/test/java/io/netty/buffer/PooledLittleEndianDirectByteBufTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012 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 java.nio.ByteOrder; + +import static org.junit.Assert.*; + +/** + * Tests little-endian direct channel buffers + */ +public class PooledLittleEndianDirectByteBufTest extends AbstractByteBufTest { + + private ByteBuf buffer; + + @Override + protected ByteBuf newBuffer(int length) { + buffer = PooledByteBufAllocator.DEFAULT.directBuffer(length).order(ByteOrder.LITTLE_ENDIAN); + assertSame(ByteOrder.LITTLE_ENDIAN, buffer.order()); + assertEquals(0, buffer.writerIndex()); + return buffer; + } + + @Override + protected ByteBuf[] components() { + return new ByteBuf[] { buffer }; + } +} diff --git a/buffer/src/test/java/io/netty/buffer/PooledLittleEndianHeapByteBufTest.java b/buffer/src/test/java/io/netty/buffer/PooledLittleEndianHeapByteBufTest.java new file mode 100644 index 0000000000..e1811665d4 --- /dev/null +++ b/buffer/src/test/java/io/netty/buffer/PooledLittleEndianHeapByteBufTest.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 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 java.nio.ByteOrder; + +import static org.junit.Assert.*; + +/** + * Tests little-endian heap channel buffers + */ +public class PooledLittleEndianHeapByteBufTest extends AbstractByteBufTest { + + private ByteBuf buffer; + + @Override + protected ByteBuf newBuffer(int length) { + buffer = PooledByteBufAllocator.DEFAULT.heapBuffer(length).order(ByteOrder.LITTLE_ENDIAN); + assertEquals(0, buffer.writerIndex()); + return buffer; + } + + @Override + protected ByteBuf[] components() { + return new ByteBuf[] { buffer }; + } +} diff --git a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java index d780a4ec95..281a737768 100644 --- a/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java +++ b/codec/src/main/java/io/netty/handler/codec/ReplayingDecoderBuffer.java @@ -106,6 +106,16 @@ final class ReplayingDecoderBuffer implements ByteBuf { throw new UnsupportedOperationException(); } + @Override + public boolean hasMemoryAddress() { + return false; + } + + @Override + public long memoryAddress() { + throw new UnsupportedOperationException(); + } + @Override public ByteBuf clear() { throw new UnreplayableOperationException();