diff --git a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java index 1ec4afa71f..92e4a471bd 100644 --- a/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java @@ -38,7 +38,7 @@ public abstract class AbstractByteBuf extends ByteBuf { static final ResourceLeakDetector leakDetector = new ResourceLeakDetector(ByteBuf.class); int readerIndex; - private int writerIndex; + int writerIndex; private int markedReaderIndex; private int markedWriterIndex; @@ -321,11 +321,18 @@ public abstract class AbstractByteBuf extends ByteBuf { SwappedByteBuf swappedBuf = this.swappedBuf; if (swappedBuf == null) { - this.swappedBuf = swappedBuf = new SwappedByteBuf(this); + this.swappedBuf = swappedBuf = newSwappedByteBuf(); } return swappedBuf; } + /** + * Creates a new {@link SwappedByteBuf} for this {@link ByteBuf} instance. + */ + protected SwappedByteBuf newSwappedByteBuf() { + return new SwappedByteBuf(this); + } + @Override public byte getByte(int index) { checkIndex(index); diff --git a/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java index 4d15509021..795335e4c3 100644 --- a/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/PooledUnsafeDirectByteBuf.java @@ -381,4 +381,9 @@ final class PooledUnsafeDirectByteBuf extends PooledByteBuf { private long addr(int index) { return memoryAddress + index; } + + @Override + protected SwappedByteBuf newSwappedByteBuf() { + return new UnsafeDirectSwappedByteBuf(this, memoryAddress); + } } diff --git a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java index a11538117e..3c917c4f84 100644 --- a/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/SwappedByteBuf.java @@ -27,7 +27,7 @@ import java.nio.charset.Charset; /** * Wrapper which swap the {@link ByteOrder} of a {@link ByteBuf}. */ -public final class SwappedByteBuf extends ByteBuf { +public class SwappedByteBuf extends ByteBuf { private final ByteBuf buf; private final ByteOrder order; diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java index 89df31acde..9b6cb76f78 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledUnsafeDirectByteBuf.java @@ -514,4 +514,9 @@ public class UnpooledUnsafeDirectByteBuf extends AbstractReferenceCountedByteBuf long addr(int index) { return memoryAddress + index; } + + @Override + protected SwappedByteBuf newSwappedByteBuf() { + return new UnsafeDirectSwappedByteBuf(this, memoryAddress); + } } diff --git a/buffer/src/main/java/io/netty/buffer/UnsafeDirectSwappedByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnsafeDirectSwappedByteBuf.java new file mode 100644 index 0000000000..5c346f3894 --- /dev/null +++ b/buffer/src/main/java/io/netty/buffer/UnsafeDirectSwappedByteBuf.java @@ -0,0 +1,181 @@ +/* +* 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; + +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; + private final long memoryAddress; + + UnsafeDirectSwappedByteBuf(AbstractByteBuf buf, long memoryAddress) { + super(buf); + wrapped = buf; + this.memoryAddress = memoryAddress; + nativeByteOrder = NATIVE_ORDER == (order() == ByteOrder.BIG_ENDIAN); + } + + private long addr(int index) { + return memoryAddress + index; + } + + @Override + public long getLong(int index) { + wrapped.checkIndex(index, 8); + long v = PlatformDependent.getLong(addr(index)); + return nativeByteOrder? v : Long.reverseBytes(v); + } + + @Override + public float getFloat(int index) { + return Float.intBitsToFloat(getInt(index)); + } + + @Override + public double getDouble(int index) { + return Double.longBitsToDouble(getLong(index)); + } + + @Override + public char getChar(int index) { + return (char) getShort(index); + } + + @Override + public long getUnsignedInt(int index) { + return getInt(index) & 0xFFFFFFFFL; + } + + @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.ensureWritable(2); + _setShort(wrapped.writerIndex, value); + wrapped.writerIndex += 2; + return this; + } + + @Override + public ByteBuf writeInt(int value) { + wrapped.ensureWritable(4); + _setInt(wrapped.writerIndex, value); + wrapped.writerIndex += 4; + return this; + } + + @Override + public ByteBuf writeLong(long value) { + 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)); + } +} diff --git a/microbench/pom.xml b/microbench/pom.xml index f967a377d2..8b150ad3af 100644 --- a/microbench/pom.xml +++ b/microbench/pom.xml @@ -47,7 +47,13 @@ org.openjdk.jmh jmh-core - 0.4.1 + 0.8 + + + org.openjdk.jmh + jmh-generator-annprocess + 0.8 + provided diff --git a/microbench/src/test/java/io/netty/microbench/buffer/SwappedByteBufBenchmark.java b/microbench/src/test/java/io/netty/microbench/buffer/SwappedByteBufBenchmark.java new file mode 100644 index 0000000000..e359a6c23c --- /dev/null +++ b/microbench/src/test/java/io/netty/microbench/buffer/SwappedByteBufBenchmark.java @@ -0,0 +1,80 @@ +/* +* 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.microbench.buffer; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.SwappedByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.microbench.util.AbstractMicrobenchmark; +import org.openjdk.jmh.annotations.GenerateMicroBenchmark; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.nio.ByteOrder; + +@State(Scope.Benchmark) +@Warmup(iterations = 10) +@Measurement(iterations = 25) +public class SwappedByteBufBenchmark extends AbstractMicrobenchmark { + private ByteBuf swappedByteBuf; + private ByteBuf unsafeSwappedByteBuf; + + @Setup + public void setup() { + swappedByteBuf = new SwappedByteBuf(Unpooled.directBuffer(8)); + unsafeSwappedByteBuf = Unpooled.directBuffer(8).order(ByteOrder.LITTLE_ENDIAN); + if (unsafeSwappedByteBuf.getClass().equals(SwappedByteBuf.class)) { + throw new IllegalStateException("Should not use " + SwappedByteBuf.class.getSimpleName()); + } + } + + @Param("16384") + public int size; + + @GenerateMicroBenchmark + public void swappedByteBufSetInt() { + swappedByteBuf.setLong(0, size); + } + + @GenerateMicroBenchmark + public void swappedByteBufSetShort() { + swappedByteBuf.setShort(0, size); + } + + @GenerateMicroBenchmark + public void swappedByteBufSetLong() { + swappedByteBuf.setLong(0, size); + } + + @GenerateMicroBenchmark + public void unsafeSwappedByteBufSetInt() { + unsafeSwappedByteBuf.setInt(0, size); + } + + @GenerateMicroBenchmark + public void unsafeSwappedByteBufSetShort() { + unsafeSwappedByteBuf.setShort(0, size); + } + + @GenerateMicroBenchmark + public void unsafeSwappedByteBufSetLong() { + unsafeSwappedByteBuf.setLong(0, size); + } +}