diff --git a/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java b/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java
index 76d2605..f6ab7a1 100644
--- a/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java
+++ b/buffer-api/src/main/java/io/netty/buffer/api/internal/Statics.java
@@ -18,7 +18,10 @@ package io.netty.buffer.api.internal;
import io.netty.buffer.api.Buffer;
import io.netty.buffer.api.Drop;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.ref.Cleaner;
import java.nio.ByteBuffer;
@@ -38,6 +41,28 @@ public interface Statics {
return "NO_OP_DROP";
}
};
+ MethodHandle BB_SLICE_OFFSETS = getByteBufferSliceOffsetsMethodHandle();
+ MethodHandle BB_PUT_OFFSETS = getByteBufferPutOffsetsMethodHandle();
+
+ static MethodHandle getByteBufferSliceOffsetsMethodHandle() {
+ try {
+ Lookup lookup = MethodHandles.lookup();
+ MethodType type = MethodType.methodType(ByteBuffer.class, int.class, int.class);
+ return lookup.findVirtual(ByteBuffer.class, "slice", type);
+ } catch (Exception ignore) {
+ return null;
+ }
+ }
+
+ static MethodHandle getByteBufferPutOffsetsMethodHandle() {
+ try {
+ Lookup lookup = MethodHandles.lookup();
+ MethodType type = MethodType.methodType(ByteBuffer.class, int.class, ByteBuffer.class, int.class, int.class);
+ return lookup.findVirtual(ByteBuffer.class, "put", type);
+ } catch (Exception ignore) {
+ return null;
+ }
+ }
static VarHandle findVarHandle(Lookup lookup, Class> recv, String name, Class> type) {
try {
@@ -77,16 +102,62 @@ public interface Statics {
* support Java 11.
*/
static ByteBuffer bbslice(ByteBuffer buffer, int fromOffset, int length) {
- return buffer.slice(fromOffset, length);
-// return buffer.clear().position(fromOffset).limit(fromOffset + length).slice();
+ if (BB_SLICE_OFFSETS != null) {
+ return bbsliceJdk13(buffer, fromOffset, length);
+ }
+ return bbsliceFallback(buffer, fromOffset, length);
+ }
+
+ private static ByteBuffer bbsliceJdk13(ByteBuffer buffer, int fromOffset, int length) {
+ try {
+ return (ByteBuffer) BB_SLICE_OFFSETS.invokeExact(buffer, fromOffset, length);
+ } catch (RuntimeException re) {
+ throw re;
+ } catch (Throwable throwable) {
+ throw new LinkageError("Unexpected exception from ByteBuffer.slice(int,int).", throwable);
+ }
+ }
+
+ private static ByteBuffer bbsliceFallback(ByteBuffer buffer, int fromOffset, int length) {
+ if (fromOffset < 0) {
+ throw new IndexOutOfBoundsException("The fromOffset must be positive: " + fromOffset + '.');
+ }
+ int newLimit = fromOffset + length;
+ if (newLimit > buffer.capacity()) {
+ throw new IndexOutOfBoundsException(
+ "The limit of " + newLimit + " would be greater than capacity: " + buffer.capacity() + '.');
+ }
+ try {
+ return buffer.position(fromOffset).limit(newLimit).slice();
+ } finally {
+ buffer.clear();
+ }
}
/**
* The ByteBuffer put-buffer-with-offset-and-length method is not available in Java 11.
*/
static void bbput(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) {
- dest.put(destPos, src, srcPos, length);
-// dest.position(destPos).put(bbslice(src, srcPos, length));
+ if (BB_PUT_OFFSETS != null) {
+ bbputJdk16(dest, destPos, src, srcPos, length);
+ } else {
+ bbputFallback(dest, destPos, src, srcPos, length);
+ }
+ }
+
+ private static void bbputJdk16(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) {
+ try {
+ @SuppressWarnings("unused") // We need to cast the return type in order to invokeExact.
+ ByteBuffer ignore = (ByteBuffer) BB_PUT_OFFSETS.invokeExact(dest, destPos, src, srcPos, length);
+ } catch (RuntimeException re) {
+ throw re;
+ } catch (Throwable throwable) {
+ throw new LinkageError("Unexpected exception from ByteBuffer.put(int,ByteBuffer,int,int).", throwable);
+ }
+ }
+
+ private static void bbputFallback(ByteBuffer dest, int destPos, ByteBuffer src, int srcPos, int length) {
+ dest.position(destPos).put(bbslice(src, srcPos, length));
}
static IllegalStateException bufferIsClosed() {
diff --git a/buffer-memseg-dummy/pom.xml b/buffer-memseg-dummy/pom.xml
new file mode 100644
index 0000000..1c1a759
--- /dev/null
+++ b/buffer-memseg-dummy/pom.xml
@@ -0,0 +1,30 @@
+
+
+
+ 4.0.0
+
+
+ io.netty.incubator
+ netty-incubator-buffer-parent
+ 0.0.1.Final-SNAPSHOT
+
+
+ netty-incubator-buffer-memseg-dummy
+ 0.0.1.Final-SNAPSHOT
+
diff --git a/buffer-memseg-dummy/src/main/java/module-info.java b/buffer-memseg-dummy/src/main/java/module-info.java
new file mode 100644
index 0000000..bc63aed
--- /dev/null
+++ b/buffer-memseg-dummy/src/main/java/module-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 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:
+ *
+ * https://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.
+ */
+module netty.incubator.buffer.memseg {
+ // Java 11 compatible stand-in module for the memory segment implementation.
+ // We need this module in order for the tests module to pull in the memseg module.
+}
diff --git a/buffer-tests/pom.xml b/buffer-tests/pom.xml
index 2d05e9a..2ed3b2d 100644
--- a/buffer-tests/pom.xml
+++ b/buffer-tests/pom.xml
@@ -1,4 +1,19 @@
+
@@ -92,5 +107,17 @@
+
+ Java 11 support for tests
+
+ !17
+
+
+
+ io.netty.incubator
+ netty-incubator-buffer-memseg-dummy
+
+
+
\ No newline at end of file
diff --git a/buffer-tests/src/main/java/module-info.java b/buffer-tests/src/main/java/module-info.java
index 7c72be3..2560866 100644
--- a/buffer-tests/src/main/java/module-info.java
+++ b/buffer-tests/src/main/java/module-info.java
@@ -21,5 +21,7 @@ open module netty.incubator.buffer.tests {
requires static java.logging;
requires netty.incubator.buffer;
- requires static netty.incubator.buffer.memseg;
+ // We need to require memseg in order for its implementation to be service loaded.
+ // Just having it on the module path is not enough.
+ requires netty.incubator.buffer.memseg;
}
diff --git a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReferenceCountingTest.java b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReferenceCountingTest.java
index f7f2515..147d936 100644
--- a/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReferenceCountingTest.java
+++ b/buffer-tests/src/test/java/io/netty/buffer/api/tests/BufferReferenceCountingTest.java
@@ -266,6 +266,7 @@ public class BufferReferenceCountingTest extends BufferTestSupport {
try (BufferAllocator allocator = fixture.createAllocator();
Buffer buf = allocator.allocate(8)) {
assertThrows(IllegalArgumentException.class, () -> buf.slice(0, -1));
+ assertThrows(IllegalArgumentException.class, () -> buf.slice(2, -1));
// Verify that the slice is closed properly afterwards.
assertTrue(buf.isOwned());
}
diff --git a/pom.xml b/pom.xml
index 5d343b4..4ea1568 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,6 +105,15 @@
buffer-memseg
+
+ Java 11 support for tests
+
+ !17
+
+
+ buffer-memseg-dummy
+
+
@@ -383,6 +392,11 @@
netty-incubator-buffer-memseg
${project.version}
+
+ io.netty.incubator
+ netty-incubator-buffer-memseg-dummy
+ ${project.version}
+
io.netty