diff --git a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java index af581cf6e7a29..486d25a6c224e 100644 --- a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java +++ b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java @@ -23,10 +23,12 @@ import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageSystemPropertyBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.UnsafeAccessedFieldBuildItem; import io.quarkus.netty.BossEventLoopGroup; import io.quarkus.netty.MainEventLoopGroup; +import io.quarkus.netty.runtime.EmptyByteBufStub; import io.quarkus.netty.runtime.NettyRecorder; class NettyProcessor { @@ -218,4 +220,10 @@ public List unsafeAccessedFields() { new UnsafeAccessedFieldBuildItem("sun.nio.ch.SelectorImpl", "selectedKeys"), new UnsafeAccessedFieldBuildItem("sun.nio.ch.SelectorImpl", "publicSelectedKeys")); } + + @BuildStep + RuntimeInitializedClassBuildItem runtimeInitBcryptUtil() { + // this holds a direct allocated byte buffer that needs to be initialised at run time + return new RuntimeInitializedClassBuildItem(EmptyByteBufStub.class.getName()); + } } diff --git a/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/EmptyByteBufStub.java b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/EmptyByteBufStub.java new file mode 100644 index 0000000000000..8a0ec95a3cdca --- /dev/null +++ b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/EmptyByteBufStub.java @@ -0,0 +1,33 @@ +package io.quarkus.netty.runtime; + +import java.nio.ByteBuffer; + +import io.netty.util.internal.PlatformDependent; + +public final class EmptyByteBufStub { + private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocateDirect(0); + private static final long EMPTY_BYTE_BUFFER_ADDRESS; + + static { + long emptyByteBufferAddress = 0; + try { + if (PlatformDependent.hasUnsafe()) { + emptyByteBufferAddress = PlatformDependent.directBufferAddress(EMPTY_BYTE_BUFFER); + } + } catch (Throwable t) { + // Ignore + } + EMPTY_BYTE_BUFFER_ADDRESS = emptyByteBufferAddress; + } + + public static ByteBuffer emptyByteBuffer() { + return EMPTY_BYTE_BUFFER; + } + + public static long emptyByteBufferAddress() { + return EMPTY_BYTE_BUFFER_ADDRESS; + } + + private EmptyByteBufStub() { + } +} diff --git a/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java index 298966b37ec11..bb629e7d0c268 100644 --- a/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java +++ b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java @@ -1,5 +1,6 @@ package io.quarkus.netty.runtime.graal; +import java.nio.ByteBuffer; import java.security.PrivateKey; import java.security.Provider; import java.security.cert.X509Certificate; @@ -35,6 +36,7 @@ import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.JdkLoggerFactory; +import io.quarkus.netty.runtime.EmptyByteBufStub; /** * This substitution avoid having loggers added to the build @@ -389,6 +391,48 @@ static Class tryToLoadClass(final ClassLoader loader, final Class helper) } +@TargetClass(className = "io.netty.buffer.EmptyByteBuf") +final class Target_io_netty_buffer_EmptyByteBuf { + + @Alias + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) + private static ByteBuffer EMPTY_BYTE_BUFFER; + + @Alias + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset) + private static long EMPTY_BYTE_BUFFER_ADDRESS; + + @Substitute + public ByteBuffer nioBuffer() { + return EmptyByteBufStub.emptyByteBuffer(); + } + + @Substitute + public ByteBuffer[] nioBuffers() { + return new ByteBuffer[] { EmptyByteBufStub.emptyByteBuffer() }; + } + + @Substitute + public ByteBuffer internalNioBuffer(int index, int length) { + return EmptyByteBufStub.emptyByteBuffer(); + } + + @Substitute + public boolean hasMemoryAddress() { + return EmptyByteBufStub.emptyByteBufferAddress() != 0; + } + + @Substitute + public long memoryAddress() { + if (hasMemoryAddress()) { + return EmptyByteBufStub.emptyByteBufferAddress(); + } else { + throw new UnsupportedOperationException(); + } + } + +} + class NettySubstitutions { }