@@ -754,151 +754,6 @@ public void visit(int version, int access, String name, String signature,
754754 .build ());
755755 }
756756
757- /**
758- * Rewrites {@code PlatformDependent#estimateMaxDirectMemory()} to replace the
759- * reflection-based VM argument lookup with direct calls. The original code uses
760- * {@code Class.forName} + {@code MethodHandles.publicLookup().findStatic/findVirtual}
761- * to call {@code ManagementFactory.getRuntimeMXBean().getInputArguments()} because
762- * "Android doesn't have these classes". Since we target JDK 17+, these are always available.
763- * <p>
764- * Using ASM's tree API, we surgically replace the instruction sequence that performs
765- * the reflection with a direct invocation, preserving all surrounding code (the loop,
766- * the regex matching, the switch, the logging).
767- */
768- @ BuildStep
769- void transformPlatformDependentEstimateMaxDirectMemory (BuildProducer <BytecodeTransformerBuildItem > producer ) {
770- String className = PlatformDependent .class .getName ();
771-
772- producer .produce (new BytecodeTransformerBuildItem .Builder ()
773- .setClassToTransform (className )
774- .setCacheable (true )
775- .setClassReaderOptions (ClassReader .EXPAND_FRAMES )
776- .setVisitorFunction (new BiFunction <>() {
777- @ Override
778- public ClassVisitor apply (String s , ClassVisitor classVisitor ) {
779- return new ClassVisitor (Gizmo .ASM_API_VERSION , classVisitor ) {
780- @ Override
781- public MethodVisitor visitMethod (int access , String name , String descriptor ,
782- String signature , String [] exceptions ) {
783- MethodVisitor mv = super .visitMethod (access , name , descriptor ,
784- signature , exceptions );
785- if ("estimateMaxDirectMemory" .equals (name ) && "()J" .equals (descriptor )) {
786- MethodVisitor target = mv ;
787- return new MethodNode (Gizmo .ASM_API_VERSION , access , name , descriptor ,
788- signature , exceptions ) {
789- @ Override
790- public void visitEnd () {
791- super .visitEnd ();
792- patchEstimateMaxDirectMemory (this .instructions );
793- this .accept (target );
794- }
795- };
796- }
797- return mv ;
798- }
799- };
800- }
801- })
802- .build ());
803- }
804-
805- /**
806- * Replaces the reflection-based sequence in {@code estimateMaxDirectMemory} with direct calls.
807- * <p>
808- * Finds and replaces:
809- *
810- * <pre>
811- * invokestatic getSystemClassLoader -> astore X
812- * ldc "java.lang.management.ManagementFactory"
813- * ... Class.forName ...
814- * ... Class.forName ...
815- * ... MethodHandles.publicLookup ...
816- * ... lookup.findStatic ...
817- * ... lookup.findVirtual ...
818- * ... getInputArguments.invoke(getRuntime.invoke()) ...
819- * checkcast List -> astore Y (vmArgs)
820- * </pre>
821- *
822- * with:
823- *
824- * <pre>
825- * invokestatic ManagementFactory.getRuntimeMXBean()
826- * invokeinterface RuntimeMXBean.getInputArguments()
827- * astore Y (vmArgs)
828- * </pre>
829- *
830- * The approach: find the {@code invokestatic getSystemClassLoader} that starts the block
831- * and the {@code checkcast java/util/List} that ends it, remove everything in between,
832- * and insert the direct calls before the checkcast (which becomes a no-op but is harmless).
833- */
834- private static void patchEstimateMaxDirectMemory (org .objectweb .asm .tree .InsnList instructions ) {
835- // Find the invokestatic getSystemClassLoader call that starts the reflection block
836- AbstractInsnNode startNode = null ;
837- for (AbstractInsnNode node = instructions .getFirst (); node != null ; node = node .getNext ()) {
838- if (node instanceof MethodInsnNode methodInsn
839- && methodInsn .getOpcode () == Opcodes .INVOKESTATIC
840- && "getSystemClassLoader" .equals (methodInsn .name )) {
841- startNode = node ;
842- break ;
843- }
844- }
845- if (startNode == null ) {
846- throw new IllegalStateException (
847- "Could not find getSystemClassLoader call in PlatformDependent.estimateMaxDirectMemory. "
848- + "The bytecode pattern may have changed in a Netty update." );
849- }
850-
851- // Find the last MethodHandle.invoke call that ends the reflection block.
852- // The sequence ends with: invokevirtual MethodHandle.invoke -> astore (vmArgs).
853- // We keep the astore and replace everything before it.
854- AbstractInsnNode lastInvoke = null ;
855- for (AbstractInsnNode node = startNode .getNext (); node != null ; node = node .getNext ()) {
856- if (node instanceof MethodInsnNode methodInsn
857- && "invoke" .equals (methodInsn .name )
858- && "java/lang/invoke/MethodHandle" .equals (methodInsn .owner )) {
859- lastInvoke = node ;
860- }
861- // Stop scanning once we pass the reflection block (next invokestatic is
862- // getMaxDirectMemorySizeArgPattern)
863- if (node instanceof MethodInsnNode methodInsn
864- && "getMaxDirectMemorySizeArgPattern" .equals (methodInsn .name )) {
865- break ;
866- }
867- }
868- if (lastInvoke == null ) {
869- throw new IllegalStateException (
870- "Could not find MethodHandle.invoke in PlatformDependent.estimateMaxDirectMemory. "
871- + "The bytecode pattern may have changed in a Netty update." );
872- }
873-
874- // The astore after the last invoke stores vmArgs - we keep it
875- AbstractInsnNode astoreNode = nextRealInsn (lastInvoke );
876-
877- // Remove everything from startNode through lastInvoke (inclusive)
878- AbstractInsnNode current = startNode ;
879- while (current != astoreNode ) {
880- AbstractInsnNode next = current .getNext ();
881- instructions .remove (current );
882- current = next ;
883- }
884-
885- // Insert direct calls before the astore:
886- // invokestatic ManagementFactory.getRuntimeMXBean() -> RuntimeMXBean
887- // invokeinterface RuntimeMXBean.getInputArguments() -> List
888- instructions .insertBefore (astoreNode , new MethodInsnNode (
889- Opcodes .INVOKESTATIC ,
890- "java/lang/management/ManagementFactory" ,
891- "getRuntimeMXBean" ,
892- "()Ljava/lang/management/RuntimeMXBean;" ,
893- false ));
894- instructions .insertBefore (astoreNode , new MethodInsnNode (
895- Opcodes .INVOKEINTERFACE ,
896- "java/lang/management/RuntimeMXBean" ,
897- "getInputArguments" ,
898- "()Ljava/util/List;" ,
899- true ));
900- }
901-
902757 /**
903758 * Rewrites {@code DefaultChannelId#processHandlePid(ClassLoader)} to avoid reflection as we target Java 21+.
904759 * <p>
0 commit comments