Skip to content

Commit

Permalink
fix some java 7 issues
Browse files Browse the repository at this point in the history
  • Loading branch information
wagyourtail committed Jun 9, 2024
1 parent 91e98f1 commit fb435ff
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 39 deletions.
27 changes: 27 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,33 @@ tasks.test {
)
}

val test7 by tasks.registering(Test::class) {
group = "verification"
description = "Runs the tests for Java 7"
testClassesDirs = sourceSets["test"].output.classesDirs
classpath = sourceSets["test"].runtimeClasspath
useJUnitPlatform()

dependsOn(
project(":downgradetest").tasks.build,
project(":java-api").tasks.build
)
javaLauncher = javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(testVersion.toInt()))
}

jvmArgs(
"-Djvmdg.test.jvm=" + javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(testVersion.toInt()))
}.get().executablePath.toString(),
"-Djvmdg.test.targetJvm=" + javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(7))
}.get().executablePath.toString(),
"-Djvmdg.test.javaVersion=7",
"-Djvmdg.test.version=$version",
)
}

project.evaluationDependsOnChildren()

val shadowJar by tasks.registering(ShadowJar::class) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public String apply(String s) {
}
};
System.out.println(test8.apply("test8"));

TestInterface<String, String> at = (a) -> a + ".5";
TestInterface<String, Double> bt = Double::parseDouble;
TestInterface<String, Double> ct = at.andThen(bt);
System.out.println(ct.get("1"));
}

public static String test2() {
Expand Down Expand Up @@ -67,4 +72,14 @@ public String get() {
}
}

public interface TestInterface<A, B> {

B get(A a);

default <C> TestInterface<A, C> andThen(TestInterface<B, C> after) {
return (a) -> after.get(get(a));
}

}

}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ kotlin.code.style=official
org.gradle.jvmargs=-Xmx4G
org.gradle.parallel=true

version=0.7.1
version=0.7.2

asm_version=9.7

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static void makeLambdaInnerClass(MethodNode mnode, int i, ClassNode cnode
mv.visitEnd();

// replace invokedynamic with method call
mnode.instructions.set(indy, new MethodInsnNode(Opcodes.INVOKESTATIC, cnode.name, "jvmdowngrader$lambda$" + mnode.name.replace("<", "$").replace(">", "$") + "$" + nextAnonymous, constructor.getDescriptor(), false));
mnode.instructions.set(indy, new MethodInsnNode(Opcodes.INVOKESTATIC, cnode.name, "jvmdowngrader$lambda$" + mnode.name.replace("<", "$").replace(">", "$") + "$" + nextAnonymous, constructor.getDescriptor(), (cnode.access & Opcodes.ACC_INTERFACE) != 0));
}

@Stub(ref = @Ref(value = "Ljava/lang/invoke/LambdaMetafactory;", member = "altMetafactory", desc = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"))
Expand Down Expand Up @@ -119,6 +119,7 @@ public static ClassNode lambdaMetafactoryCreatorInternal(String parentName, Type
args[0] = Type.getObjectType(invokedMethod.getOwner());
System.arraycopy(virtArgs, 0, args, 1, virtArgs.length);
}
Type ret = Type.getReturnType(invokedMethod.getDesc());

int n = 0;
// load fields back into stack
Expand Down Expand Up @@ -157,7 +158,8 @@ public static ClassNode lambdaMetafactoryCreatorInternal(String parentName, Type
}
// invoke original synthetic created for lambda
mv.visitMethodInsn(opcode, invokedMethod.getOwner(), invokedMethod.getName(), invokedMethod.getDesc(), invokedMethod.isInterface());
mv.visitInsn(bridge.getReturnType().getOpcode(Opcodes.IRETURN));
doCast(mv, invokedType.getReturnType(), ret);
mv.visitInsn(invokedType.getReturnType().getOpcode(Opcodes.IRETURN));
mv.visitMaxs(0, 0);
mv.visitEnd();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,14 @@ public void init() {

@Override
public ClassNode otherTransforms(ClassNode clazz, Set<ClassNode> extra, Function<String, ClassNode> getReadOnly) {
try {
downgradeInterfaces(clazz, extra, getReadOnly);
} catch (IOException e) {
throw new RuntimeException(e);
List<ClassNode> classes = new ArrayList<>(extra);
classes.add(clazz);
for (ClassNode cls : classes) {
try {
downgradeInterfaces(cls, extra, getReadOnly);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return super.otherTransforms(clazz, extra, getReadOnly);
}
Expand All @@ -357,11 +361,11 @@ private void downgradeInterfaceMethods(final ClassNode clazz, Set<ClassNode> ext
mnodes.remove();
removed = true;
if ((mnode.access & Opcodes.ACC_STATIC) == 0) {
// instance method
if ((mnode.access & Opcodes.ACC_PRIVATE) == 0) {
// public instance method
if ((mnode.access & Opcodes.ACC_PUBLIC) != 0) {
// write back an abstract version
toAdd.add(new MethodNode(
mnode.access | Opcodes.ACC_ABSTRACT,
Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
mnode.name,
mnode.desc,
mnode.signature,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,29 +99,32 @@ public byte[] apply(String s) {
// doesn't need downgrading
return defineClass(name, bytes, 0, bytes.length);
}
for (Map.Entry<String, byte[]> entry : outputs.entrySet()) {
if (entry.getKey().equals(internalName)) continue; // skip the main class (load later and returned)
String extraName = entry.getKey().replace('/', '.');
byte[] extraBytes = entry.getValue();
try {
defineClass(extraName, extraBytes, 0, extraBytes.length);
} catch (ClassFormatError e) {
currentVersionDowngrader.writeBytesToDebug(extraName, bytes);
throw e;
}
}
Class<?> returnValue;
try {
bytes = outputs.get(internalName);
if (bytes == null) {
throw new ClassNotFoundException("removed by downgrader: " + name);
}
return defineClass(name, bytes, 0, bytes.length);
returnValue = defineClass(name, bytes, 0, bytes.length);
} catch (ClassFormatError e) {
currentVersionDowngrader.writeBytesToDebug(name, bytes);
// System.err.println("Failed to load class " + name + " with downgraded bytes, writing to debug folder.");
// throw e;
throw new ClassNotFoundException(name, e);
}
for (Map.Entry<String, byte[]> entry : outputs.entrySet()) {
if (entry.getKey().equals(internalName)) continue; // skip the main class (load later and returned)
String extraName = entry.getKey().replace('/', '.');
byte[] extraBytes = entry.getValue();
try {
defineClass(extraName, extraBytes, 0, extraBytes.length);
} catch (ClassFormatError | ClassCircularityError e) {
System.err.println("Failed to load class " + extraName + " with downgraded bytes, writing to debug folder.");
currentVersionDowngrader.writeBytesToDebug(extraName, bytes);
throw e;
}
}
return returnValue;
} catch (ClassFormatError e) {
currentVersionDowngrader.writeBytesToDebug(name, bytes);
// System.err.println("Failed to load class " + name + " with original bytes, writing to debug folder.");
Expand Down
70 changes: 61 additions & 9 deletions src/main/java/xyz/wagyourtail/jvmdg/version/VersionProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -696,13 +696,13 @@ public boolean isInitialized() {
return initialized;
}

public ClassNode downgrade(final ClassDowngrader downgrader, ClassNode clazz, Set<ClassNode> extra, boolean enableRuntime, final Function<String, ClassNode> getReadOnly) throws IOException {
public ClassNode downgrade(final ClassDowngrader downgrader, ClassNode clazz, final Set<ClassNode> extra, final boolean enableRuntime, final Function<String, ClassNode> getReadOnly) throws IOException {
if (clazz.version != inputVersion)
throw new IllegalArgumentException("Class " + clazz.name + " is not version " + inputVersion);

ensureInit(downgrader);

IOFunction<Type, Set<MemberNameAndDesc>> getMembers = new IOFunction<Type, Set<MemberNameAndDesc>>() {
final IOFunction<Type, Set<MemberNameAndDesc>> getMembers = new IOFunction<Type, Set<MemberNameAndDesc>>() {
@Override
public Set<MemberNameAndDesc> apply(Type o) throws IOException {
Set<MemberNameAndDesc> members = downgrader.getMembers(inputVersion, o);
Expand All @@ -717,11 +717,23 @@ public Set<MemberNameAndDesc> apply(Type o) throws IOException {
}
}
}
// if not found in read-only, check extra
if (members == null) {
for (ClassNode extraClass : extra) {
if (extraClass.name.equals(o.getInternalName())) {
members = new HashSet<>();
for (MethodNode method : extraClass.methods) {
if ((method.access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_PRIVATE)) != 0) continue;
members.add(new MemberNameAndDesc(method.name, downgrader.stubClass(extraClass.version, Type.getMethodType(method.desc))));
}
}
}
}
return members;
}
};

IOFunction<Type, List<Pair<Type, Boolean>>> getSuperTypes = new IOFunction<Type, List<Pair<Type, Boolean>>>() {
final IOFunction<Type, List<Pair<Type, Boolean>>> getSuperTypes = new IOFunction<Type, List<Pair<Type, Boolean>>>() {

@Override
public List<Pair<Type, Boolean>> apply(Type o) throws IOException {
Expand All @@ -733,7 +745,19 @@ public List<Pair<Type, Boolean>> apply(Type o) throws IOException {
types = new ArrayList<>();
types.add(new Pair<>(downgrader.stubClass(ro.version, Type.getObjectType(ro.superName)), Boolean.FALSE));
for (String anInterface : ro.interfaces) {
types.add(new Pair<>(Type.getObjectType(anInterface), Boolean.TRUE));
types.add(new Pair<>(downgrader.stubClass(ro.version, Type.getObjectType(anInterface)), Boolean.TRUE));
}
}
}
// if not found in read-only, check extra
if (types == null) {
for (ClassNode extraClass : extra) {
if (extraClass.name.equals(o.getInternalName())) {
types = new ArrayList<>();
types.add(new Pair<>(downgrader.stubClass(extraClass.version, Type.getObjectType(extraClass.superName)), Boolean.FALSE));
for (String anInterface : extraClass.interfaces) {
types.add(new Pair<>(downgrader.stubClass(extraClass.version, Type.getObjectType(anInterface)), Boolean.TRUE));
}
}
}
}
Expand All @@ -743,22 +767,50 @@ public List<Pair<Type, Boolean>> apply(Type o) throws IOException {

clazz = stubClasses(clazz, enableRuntime);
if (clazz == null) return null;
clazz = stubMethods(clazz, extra, enableRuntime, getMembers, getSuperTypes);
clazz = stubWithExtras(clazz, extra, new IOFunction<ClassNode, ClassNode>() {
@Override
public ClassNode apply(ClassNode classNode) throws IOException {
return stubMethods(classNode, extra, enableRuntime, getMembers, getSuperTypes);
}
});
if (clazz == null) return null;
clazz = insertAbstractMethods(clazz, extra, getMembers, getSuperTypes);
clazz = stubWithExtras(clazz, extra, new IOFunction<ClassNode, ClassNode>() {
@Override
public ClassNode apply(ClassNode classNode) throws IOException {
return insertAbstractMethods(classNode, extra, getMembers, getSuperTypes);
}
});
if (clazz == null) return null;
clazz = otherTransforms(clazz, extra, getReadOnly);
clazz = stubWithExtras(clazz, extra, new IOFunction<ClassNode, ClassNode>() {
@Override
public ClassNode apply(ClassNode classNode) throws IOException {
return otherTransforms(classNode, extra, getReadOnly);
}
});
if (clazz == null) return null;
clazz.version = inputVersion - 1;
return clazz;
}

public ClassNode stubWithExtras(ClassNode clazz, Set<ClassNode> extra, IOFunction<ClassNode, ClassNode> stubber) throws IOException {
clazz = stubber.apply(clazz);
if (clazz == null) return null;
for (ClassNode extraClass : new ArrayList<>(extra)) {
ClassNode extraRemapped = stubber.apply(extraClass);
extra.remove(extraClass);
if (extraRemapped == null) continue;
extra.add(extraRemapped);
}
return clazz;
}

public ClassNode insertAbstractMethods(ClassNode clazz, Set<ClassNode> extra, IOFunction<Type, Set<MemberNameAndDesc>> getMembers, IOFunction<Type, List<Pair<Type, Boolean>>> getSuperTypes) throws IOException {
if (clazz.name.equals("module-info")) {
return clazz;
}

Map<MemberNameAndDesc, Pair<Method, Stub>> members = getStubMapper(Type.getObjectType(clazz.name), (clazz.access & Opcodes.ACC_INTERFACE) != 0, getMembers, getSuperTypes).getAbstracts();
ClassMapping cm = getStubMapper(Type.getObjectType(clazz.name), (clazz.access & Opcodes.ACC_INTERFACE) != 0, getMembers, getSuperTypes);
cm.getMembers();
Map<MemberNameAndDesc, Pair<Method, Stub>> members = cm.getAbstracts();
for (Map.Entry<MemberNameAndDesc, Pair<Method, Stub>> member : members.entrySet()) {
boolean contains = false;
for (MethodNode method : clazz.methods) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,29 @@


public class JvmDowngraderTest {
private static final Flags flags = new Flags();
private static final Path javaApi = Path.of("./java-api/build/libs/jvmdowngrader-java-api-" + System.getProperty("jvmdg.test.version") + ".jar");

static {
// System.setProperty("jvmdg.java-api", javaApi.toString());
flags.api = javaApi.toFile();
}
private final Flags flags = new Flags();

private final JavaRunner.JavaVersion target = JavaRunner.JavaVersion.fromMajor(Integer.parseInt(System.getProperty("jvmdg.test.javaVersion")));

private final Path mainClasses = Path.of("./build/classes/java/main");

private final Path original = Path.of("./downgradetest/build/libs/downgradetest-1.0.0.jar");
private final Path downgraded;
private final Path downgradedJavaApi;

private final Path downgraded = getDowngradedPath(original, "-downgraded-" + target.getMajorVersion() + ".jar");
private final Path downgradedJavaApi = getDowngradedJavaApi(javaApi, "-downgraded-" + target.getMajorVersion() + ".jar");
private final Path shaded;

// System.setProperty("jvmdg.java-api", javaApi.toString());

private final Path shaded = getShadedPath(downgraded, downgradedJavaApi, "-shaded.jar");

public JvmDowngraderTest() throws Exception {
flags.api = javaApi.toFile();
flags.classVersion = target.toOpcode();
downgraded = getDowngradedPath(original, "-downgraded-" + target.getMajorVersion() + ".jar");
downgradedJavaApi = getDowngradedJavaApi(javaApi, "-downgraded-" + target.getMajorVersion() + ".jar");
shaded = getShadedPath(downgraded, downgradedJavaApi, "-shaded.jar");
}

private Path getDowngradedPath(Path originalPath, String suffix) throws Exception {
Expand Down

0 comments on commit fb435ff

Please sign in to comment.