Skip to content

Commit

Permalink
fix java7downgrader
Browse files Browse the repository at this point in the history
  • Loading branch information
wagyourtail committed Nov 25, 2024
1 parent fecdf7d commit 978dee0
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package xyz.wagyourtail.jvmdg.providers;

import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringType;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import xyz.wagyourtail.jvmdg.ClassDowngrader;
import xyz.wagyourtail.jvmdg.asm.ASMUtils;
import xyz.wagyourtail.jvmdg.asm.AnnotationUtils;
import xyz.wagyourtail.jvmdg.j7.stub.J_L_Throwable;
import xyz.wagyourtail.jvmdg.util.Function;
import xyz.wagyourtail.jvmdg.util.IOFunction;
import xyz.wagyourtail.jvmdg.util.Pair;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.ReflectionReferences;
import xyz.wagyourtail.jvmdg.version.VersionProvider;
import xyz.wagyourtail.jvmdg.version.map.FullyQualifiedMemberNameAndDesc;
import xyz.wagyourtail.jvmdg.version.map.MemberNameAndDesc;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.*;

public class Java7Downgrader extends VersionProvider {

Expand Down Expand Up @@ -49,7 +51,8 @@ public ClassNode otherTransforms(ClassNode clazz, Set<ClassNode> extra, Function
Type methodType = stubClass(Type.getObjectType("java/lang/invoke/MethodType"), warnings);

MethodNode clinit = null;
for (MethodNode method : clazz.methods) {
List<FullyQualifiedMemberNameAndDesc> reflectionRefList = new ArrayList<>();
for (MethodNode method : new ArrayList<>(clazz.methods)) {
if (method.name.equals("<clinit>")) {
clinit = method;
}
Expand All @@ -58,19 +61,22 @@ public ClassNode otherTransforms(ClassNode clazz, Set<ClassNode> extra, Function
AbstractInsnNode insn = method.instructions.get(i);
if (insn.getType() == AbstractInsnNode.INVOKE_DYNAMIC_INSN) {
InvokeDynamicInsnNode indy = (InvokeDynamicInsnNode) insn;
String name = indyToMethodHandle(method, indy, clazz, addToClinit, callSiteType, handleType, lookupType, methodType);
String name = indyToMethod(method, indy, clazz, addToClinit, callSiteType, handleType, lookupType, methodType, reflectionRefList);
InsnList insns = new InsnList();
insns.add(new FieldInsnNode(Opcodes.GETSTATIC, clazz.name, name, handleType.getDescriptor()));
// TODO: fix if stubbing MethodHandle properly
insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, handlesType.getInternalName(), "invokeExact", indy.desc, false));
method.instructions.insertBefore(indy, insns);
method.instructions.remove(indy);

method.instructions.set(indy, new MethodInsnNode(
Opcodes.INVOKESTATIC,
clazz.name,
name,
indy.desc,
false
));
}
if (insn.getType() == AbstractInsnNode.LDC_INSN) {
assert insn instanceof LdcInsnNode;
Object cst = ((LdcInsnNode) insn).cst;
if (cst instanceof Handle) {
String name = handleToLookupField((Handle) cst, clazz, addToClinit, handleType, lookupType, methodType);
String name = handleToLookupField((Handle) cst, clazz, addToClinit, handleType, lookupType, methodType, reflectionRefList);
method.instructions.set(insn, new FieldInsnNode(Opcodes.GETSTATIC, clazz.name, name, handleType.getDescriptor()));
} else if (cst instanceof Type && ((Type) cst).getSort() == Type.METHOD) {
String name = methodDescToLookupField((Type) cst, clazz, addToClinit, methodType);
Expand All @@ -89,6 +95,32 @@ public ClassNode otherTransforms(ClassNode clazz, Set<ClassNode> extra, Function
clinit.visitEnd();
clazz.methods.add(clinit);
}
if (clinit.visibleAnnotations == null) {
clinit.visibleAnnotations = new ArrayList<>();
}
String reflectionRefs = Type.getType(ReflectionReferences.class).getDescriptor();
String refType = Type.getType(Ref.class).getDescriptor();
AnnotationNode node = null;
for (AnnotationNode a : clinit.visibleAnnotations) {
if (a.desc.equals(reflectionRefs)) {
node = a;
break;
}
}
if (node == null) {
node = new AnnotationNode(reflectionRefs);
clinit.visibleAnnotations.add(node);
node.values = new ArrayList<Object>(Arrays.asList("value", new ArrayList<AnnotationNode>()));
}
List<AnnotationNode> refs = ((List<AnnotationNode>) node.values.get(1));
for (FullyQualifiedMemberNameAndDesc ref : reflectionRefList) {
AnnotationNode refAnn = new AnnotationNode(refType);
refAnn.visit("value", ref.getOwner().getInternalName());
refAnn.visit("member", ref.getName());
refAnn.visit("desc", ref.getDesc().toString());
refAnn.visitEnd();
refs.add(refAnn);
}
Handle lookup = stubHandle(clazz, clinit, extra, null, null, enableRuntime, memberResolver, superTypeResolver, warnings,
new Handle(
Opcodes.H_INVOKESTATIC,
Expand All @@ -109,17 +141,19 @@ public ClassNode otherTransforms(ClassNode clazz, Set<ClassNode> extra, Function
return super.otherTransforms(clazz);
}

public String indyToMethodHandle(MethodNode method, InvokeDynamicInsnNode indy, ClassNode clazz, InsnList addToClinit, Type callsiteType, Type handleType, Type lookupType, Type methodType) {
public String indyToMethod(MethodNode method, InvokeDynamicInsnNode indy, ClassNode clazz, InsnList addToClinit, Type callsiteType, Type handleType, Type lookupType, Type methodType, List<FullyQualifiedMemberNameAndDesc> reflectionRefList) {
InvokeDynamicType it = new InvokeDynamicType(indy);
for (FieldNode field : clazz.fields) {
if (field instanceof IndyField && ((IndyField) field).indy.equals(it)) {
return field.name;
}
}
IndyField indyField = new IndyField(it, callsiteType);
int count = clazz.fields.size();
IndyField indyField = new IndyField(it, callsiteType, count);
clazz.fields.add(indyField);

addToClinit.add(new FieldInsnNode(Opcodes.GETSTATIC, clazz.name, "jvmdg$lookup", lookupType.getDescriptor()));
addToClinit.add(new LdcInsnNode(indy.name));
addToClinit.add(methodDescToMethodType(Type.getMethodType(indy.desc), methodType));

for (Object arg : indy.bsmArgs) {
Expand All @@ -130,17 +164,18 @@ public String indyToMethodHandle(MethodNode method, InvokeDynamicInsnNode indy,
addToClinit.add(new LdcInsnNode(arg));
}
} else if (arg instanceof Handle) {
addToClinit.add(handleToLookupStack((Handle) arg, clazz, handleType, lookupType, methodType));
addToClinit.add(handleToLookupStack((Handle) arg, clazz, handleType, lookupType, methodType, reflectionRefList));
} else {
addToClinit.add(new LdcInsnNode(arg));
}
}

addToClinit.add(new MethodInsnNode(
Opcodes.INVOKEVIRTUAL,
callsiteType.getInternalName(),
"getTarget",
Type.getMethodDescriptor(handleType)
Opcodes.INVOKESTATIC,
indy.bsm.getOwner(),
indy.bsm.getName(),
indy.bsm.getDesc(),
indy.bsm.isInterface()
));

addToClinit.add(new FieldInsnNode(
Expand All @@ -150,23 +185,49 @@ public String indyToMethodHandle(MethodNode method, InvokeDynamicInsnNode indy,
indyField.desc
));

return indyField.name;
IndyMethod indyMethod = new IndyMethod(it, count);
clazz.methods.add(indyMethod);
indyMethod.visitCode();
indyMethod.visitFieldInsn(Opcodes.GETSTATIC, clazz.name, indyField.name, callsiteType.getDescriptor());
indyMethod.visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
callsiteType.getInternalName(),
"getTarget",
Type.getMethodDescriptor(handleType),
false
);

int i = 0;
for (Type arg : Type.getArgumentTypes(indy.desc)) {
indyMethod.visitVarInsn(arg.getOpcode(Opcodes.ILOAD), i);
i += arg.getSize();
}

// TODO: fix if stubbing MethodHandle properly
indyMethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, handleType.getInternalName(), "invokeExact", indy.desc, false);
Type returnType = Type.getReturnType(indy.desc);
indyMethod.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
indyMethod.visitMaxs(0, 0);
indyMethod.visitEnd();

return indyMethod.name;
}

public String handleToLookupField(Handle handle, ClassNode clazz, InsnList addToClinit, Type handleType, Type lookupType, Type methodType) {
public String handleToLookupField(Handle handle, ClassNode clazz, InsnList addToClinit, Type handleType, Type lookupType, Type methodType, List<FullyQualifiedMemberNameAndDesc> reflectionRefList) {
for (FieldNode field : clazz.fields) {
if (field instanceof HandleField && handle.equals(((HandleField) field).handle)) {
return field.name;
}
}
HandleField field = new HandleField(handle, handleType);
HandleField field = new HandleField(handle, handleType, clazz.fields.size());
clazz.fields.add(field);
addToClinit.add(handleToLookupStack(handle, clazz, handleType, lookupType, methodType));
addToClinit.add(handleToLookupStack(handle, clazz, handleType, lookupType, methodType, reflectionRefList));
addToClinit.add(new FieldInsnNode(Opcodes.PUTSTATIC, clazz.name, field.name, field.desc));
return field.name;
}

public InsnList handleToLookupStack(Handle handle, ClassNode clazz, Type handleType, Type lookupType, Type methodType) {
public InsnList handleToLookupStack(Handle handle, ClassNode clazz, Type handleType, Type lookupType, Type methodType, List<FullyQualifiedMemberNameAndDesc> reflectionRefList) {
reflectionRefList.add(FullyQualifiedMemberNameAndDesc.of(handle));
InsnList insns = new InsnList();
insns.add(new FieldInsnNode(Opcodes.GETSTATIC, clazz.name, "jvmdg$lookup", lookupType.getDescriptor()));
insns.add(new LdcInsnNode(Type.getObjectType(handle.getOwner())));
Expand Down Expand Up @@ -298,6 +359,17 @@ public static InsnList methodDescToMethodType(Type desc, Type methodType) {
return l;
}

public static class IndyMethod extends MethodNode {
private final InvokeDynamicType indy;


public IndyMethod(InvokeDynamicType indy, int count) {
super(Opcodes.ASM9, Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, "jvmdg$indy$" + indy.indy.name + "$" + count, indy.indy.desc, null, null);
this.indy = indy;
}

}

public static class MethodTypeField extends FieldNode {
private final Type type;

Expand All @@ -310,8 +382,8 @@ public MethodTypeField(Type type, String name, Type methodType) {
public static class HandleField extends FieldNode {
private final Handle handle;

public HandleField(Handle handle, Type handleType) {
super(Opcodes.ASM9, Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "jvmdg$handle$" + handle.getOwner().replace("/", "_") + "$" + handle.getName(), handleType.getDescriptor(), null, null);
public HandleField(Handle handle, Type handleType, int count) {
super(Opcodes.ASM9, Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "jvmdg$handle$" + handle.getName() + "$" + count, handleType.getDescriptor(), null, null);
this.handle = handle;
}

Expand All @@ -320,8 +392,8 @@ public HandleField(Handle handle, Type handleType) {
public static class IndyField extends FieldNode {
private final InvokeDynamicType indy;

public IndyField(InvokeDynamicType indy, Type callsiteType) {
super(Opcodes.ASM9, Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, indy.indy.name, callsiteType.getDescriptor(), null, null);
public IndyField(InvokeDynamicType indy, Type callsiteType, int count) {
super(Opcodes.ASM9, Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "jvmdg$indy$" + indy.indy.name + "$" + count, callsiteType.getDescriptor(), null, null);
this.indy = indy;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import xyz.wagyourtail.jvmdg.util.IOConsumer;
import xyz.wagyourtail.jvmdg.util.Pair;
import xyz.wagyourtail.jvmdg.util.Utils;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.ReflectionReferences;
import xyz.wagyourtail.jvmdg.version.RequiresResource;
import xyz.wagyourtail.jvmdg.version.map.FullyQualifiedMemberNameAndDesc;
import xyz.wagyourtail.jvmdg.version.map.MemberNameAndDesc;
Expand Down Expand Up @@ -484,6 +486,16 @@ public void scan(ClassNode classNode, Filter filter) {
throw new RuntimeException(e);
}
}
if (annotation.desc.equals(Type.getDescriptor(ReflectionReferences.class))) {
try {
ReflectionReferences refs = AnnotationUtils.createAnnotation(annotation);
for (Ref ref : refs.value()) {
requiresMember(methodMember, FullyQualifiedMemberNameAndDesc.of(ref) , filter, null);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import xyz.wagyourtail.jvmdg.version.Ref;

import java.lang.reflect.Method;
import java.util.Objects;
Expand All @@ -19,6 +20,19 @@ public FullyQualifiedMemberNameAndDesc(Type owner, String name, Type desc) {
this.desc = desc;
}

public static FullyQualifiedMemberNameAndDesc of(Ref ref) {
String owner;
if (ref.value().startsWith("L") && ref.value().endsWith(";")) {
owner = ref.value().substring(1, ref.value().length() - 1);
} else {
owner = ref.value();
}
if (ref.member().isEmpty()) {
return new FullyQualifiedMemberNameAndDesc(Type.getObjectType(owner), null, null);
}
return new FullyQualifiedMemberNameAndDesc(Type.getObjectType(owner), ref.member(), Type.getType(ref.desc()));
}

public static FullyQualifiedMemberNameAndDesc of(Method method) {
return new FullyQualifiedMemberNameAndDesc(Type.getType(method.getDeclaringClass()), method.getName(), Type.getType(method));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package xyz.wagyourtail.jvmdg.version;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ReflectionReferences {

Ref[] value();

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ private static Stream<FlagsAndRunner> flags() {
flags.logLevel = Logger.Level.FATAL;

return Stream.of(
// new FlagsAndRunner(JavaRunner.JavaVersion.V1_8, flags.copy(e -> {
// e.classVersion = JavaRunner.JavaVersion.V1_5.toOpcode();
// e.shadeInlining = true;
// e.debugSkipStubs = Set.of(JavaRunner.JavaVersion.V1_8.toOpcode());
// })),
new FlagsAndRunner(JavaRunner.JavaVersion.V1_8, flags.copy(e -> {
e.classVersion = JavaRunner.JavaVersion.V1_8.toOpcode();
e.shadeInlining = true;
Expand Down

0 comments on commit 978dee0

Please sign in to comment.