Use invokedynamic

This commit is contained in:
yushijinhun 2019-01-23 20:13:25 +08:00
parent a94528bb68
commit 1003212d38
No known key found for this signature in database
GPG key ID: 5BC167F73EA558E4
6 changed files with 53 additions and 39 deletions

View file

@ -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();
}
};

View file

@ -0,0 +1,35 @@
/*
* Copyright (C) 2019 Haowei Wen <yushijinhun@gmail.com> 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 <https://www.gnu.org/licenses/>.
*/
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));
}
}

View file

@ -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());
}
}

View file

@ -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);
}
};

View file

@ -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();

View file

@ -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);