diff --git a/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java b/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java index 3776e76..36fd244 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java @@ -228,10 +228,9 @@ public class AuthlibLogInterceptor implements TransformUnit { @Override public void visitCode() { super.visitCode(); - CallbackInvocation callback = CallbackInvocation.push(ctx, mv, AuthlibLogInterceptor.class, "onClassLoading"); super.visitLdcInsn(Type.getType("L" + className.replace('.', '/') + ";")); super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); - callback.invoke(); + CallbackSupport.invoke(ctx, mv, AuthlibLogInterceptor.class, "onClassLoading"); ctx.markModified(); } }; diff --git a/src/main/java/moe/yushi/authlibinjector/transform/CallbackEntryPoint.java b/src/main/java/moe/yushi/authlibinjector/transform/CallbackEntryPoint.java new file mode 100644 index 0000000..933c5c8 --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/CallbackEntryPoint.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 Haowei Wen and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package moe.yushi.authlibinjector.transform; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; + +public final class CallbackEntryPoint { + private CallbackEntryPoint() { + } + + public static CallSite bootstrap(Lookup lookup, String name, MethodType type, String owner) throws ReflectiveOperationException { + return new ConstantCallSite( + lookup.findStatic( + ClassLoader.getSystemClassLoader().loadClass(owner), + name, + type)); + } +} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/CallbackInvocation.java b/src/main/java/moe/yushi/authlibinjector/transform/CallbackSupport.java similarity index 55% rename from src/main/java/moe/yushi/authlibinjector/transform/CallbackInvocation.java rename to src/main/java/moe/yushi/authlibinjector/transform/CallbackSupport.java index 0c84b8e..f148a17 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/CallbackInvocation.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/CallbackSupport.java @@ -16,18 +16,18 @@ */ package moe.yushi.authlibinjector.transform; -import static org.objectweb.asm.Opcodes.INVOKESTATIC; -import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.H_INVOKESTATIC; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import org.objectweb.asm.Handle; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import moe.yushi.authlibinjector.transform.TransformUnit.TransformContext; -public class CallbackInvocation { +public class CallbackSupport { private static Method findCallbackMethod(Class owner, String methodName) { for (Method method : owner.getDeclaredMethods()) { @@ -41,32 +41,18 @@ public class CallbackInvocation { throw new IllegalArgumentException("No such method: " + methodName); } - public static CallbackInvocation push(TransformContext ctx, MethodVisitor mv, Class owner, String methodName) { + private static final Handle BOOTSTRAP_METHOD = new Handle( + H_INVOKESTATIC, + Type.getInternalName(CallbackEntryPoint.class), + "bootstrap", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;", + false); + + public static void invoke(TransformContext ctx, MethodVisitor mv, Class owner, String methodName) { ctx.requireMinimumClassVersion(50); ctx.upgradeClassVersion(51); String descriptor = Type.getMethodDescriptor(findCallbackMethod(owner, methodName)); - - mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "publicLookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/ClassLoader", "getSystemClassLoader", "()Ljava/lang/ClassLoader;", false); - mv.visitLdcInsn(owner.getName()); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassLoader", "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", false); - mv.visitLdcInsn(methodName); - mv.visitLdcInsn(Type.getMethodType(descriptor)); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - - return new CallbackInvocation(mv, descriptor); - } - - private MethodVisitor mv; - private String descriptor; - - private CallbackInvocation(MethodVisitor mv, String descriptor) { - this.mv = mv; - this.descriptor = descriptor; - } - - public void invoke() { - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", descriptor, false); + mv.visitInvokeDynamicInsn(methodName, descriptor, BOOTSTRAP_METHOD, owner.getName()); } } diff --git a/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java index ef3001e..02011e2 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java @@ -48,9 +48,8 @@ public class MainArgumentsTransformer implements TransformUnit { super.visitCode(); ctx.markModified(); - CallbackInvocation callback = CallbackInvocation.push(ctx, mv, MainArgumentsTransformer.class, "processMainArguments"); super.visitVarInsn(ALOAD, 0); - callback.invoke(); + CallbackSupport.invoke(ctx, mv, MainArgumentsTransformer.class, "processMainArguments"); super.visitVarInsn(ASTORE, 0); } }; diff --git a/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java b/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java index 781810c..fdcec91 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java @@ -76,7 +76,7 @@ public class YggdrasilKeyTransformUnit implements TransformUnit { mv.visitInsn(IRETURN); mv.visitLabel(l0); mv.visitFrame(F_SAME, 0, null, 0, null); - CallbackInvocation.push(ctx, mv, YggdrasilKeyTransformUnit.class, "getPublicKeys").invoke(); + CallbackSupport.invoke(ctx, mv, YggdrasilKeyTransformUnit.class, "getPublicKeys"); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;", true); mv.visitVarInsn(ASTORE, 2); Label l1 = new Label(); diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java index 0b0c9c8..f5c0509 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java @@ -22,7 +22,6 @@ import static org.objectweb.asm.Opcodes.CHECKCAST; import static org.objectweb.asm.Opcodes.DUP; import static org.objectweb.asm.Opcodes.GETFIELD; import static org.objectweb.asm.Opcodes.INVOKESTATIC; -import static org.objectweb.asm.Opcodes.SWAP; import java.util.Map; import java.util.Optional; @@ -34,8 +33,8 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import moe.yushi.authlibinjector.AuthlibInjector; -import moe.yushi.authlibinjector.transform.CallbackInvocation; import moe.yushi.authlibinjector.transform.CallbackMethod; +import moe.yushi.authlibinjector.transform.CallbackSupport; import moe.yushi.authlibinjector.transform.MainArgumentsTransformer; import moe.yushi.authlibinjector.transform.TransformUnit; import moe.yushi.authlibinjector.util.Logging; @@ -123,9 +122,7 @@ public class MC52974_1710Workaround { if (opcode == ARETURN) { ctx.markModified(); super.visitInsn(DUP); - CallbackInvocation callback = CallbackInvocation.push(ctx, mv, MC52974_1710Workaround.class, "markGameProfile"); - super.visitInsn(SWAP); - callback.invoke(); + CallbackSupport.invoke(ctx, mv, MC52974_1710Workaround.class, "markGameProfile"); super.visitTypeInsn(CHECKCAST, "com/mojang/authlib/GameProfile"); } super.visitInsn(opcode); @@ -161,8 +158,6 @@ public class MC52974_1710Workaround { ? "gb".equals(owner) && "b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor) : "net/minecraft/network/play/server/S0CPacketSpawnPlayer".equals(owner) && "field_148955_b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor))) { ctx.markModified(); - CallbackInvocation callback = CallbackInvocation.push(ctx, mv, MC52974_1710Workaround.class, "accessGameProfile"); - super.visitInsn(SWAP); super.visitFieldInsn(opcode, owner, name, descriptor); if (isNotchName) { super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "I", "()Lnet/minecraft/server/MinecraftServer;", false); @@ -170,7 +165,7 @@ public class MC52974_1710Workaround { super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "func_71276_C", "()Lnet/minecraft/server/MinecraftServer;", false); } super.visitLdcInsn(isNotchName ? 1 : 0); - callback.invoke(); + CallbackSupport.invoke(ctx, mv, MC52974_1710Workaround.class, "accessGameProfile"); super.visitTypeInsn(CHECKCAST, "com/mojang/authlib/GameProfile"); } else { super.visitFieldInsn(opcode, owner, name, descriptor);