Skip to content

Commit

Permalink
Dynamically resolve field type changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Jul 21, 2024
1 parent 2d5468d commit 80a5ada
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,33 @@
import com.mojang.datafixers.util.Pair;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.FieldNode;
import org.sinytra.adapter.patch.util.provider.ClassLookup;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public final class BytecodeFixerUpper {
public static final List<TypeAdapterProvider> DEFAULT_PROVIDERS = List.of(
SupplierTypeAdapter.INSTANCE
);

private final Map<String, Map<String, Pair<Type, Type>>> newFieldTypes;
private final List<TypeAdapter> fieldTypeAdapters;
private final List<TypeAdapterProvider> dynamicTypeAdapters;
private final BytecodeFixerJarGenerator generator;
private final ClassLookup cleanLookup;
private final ClassLookup dirtyLookup;

public BytecodeFixerUpper(Map<String, Map<String, Pair<Type, Type>>> newFieldTypes, List<TypeAdapter> fieldTypeAdapters) {
this(newFieldTypes, fieldTypeAdapters, DEFAULT_PROVIDERS);
private final Map<String, Pair<Type, Type>> fieldTypeChangesCache = new ConcurrentHashMap<>();

public BytecodeFixerUpper(ClassLookup cleanLookup, ClassLookup dirtyLookup, List<TypeAdapter> fieldTypeAdapters) {
this(cleanLookup, dirtyLookup, fieldTypeAdapters, DEFAULT_PROVIDERS);
}

public BytecodeFixerUpper(Map<String, Map<String, Pair<Type, Type>>> newFieldTypes, List<TypeAdapter> fieldTypeAdapters, List<TypeAdapterProvider> dynamicTypeAdapters) {
this.newFieldTypes = newFieldTypes;
public BytecodeFixerUpper(ClassLookup cleanLookup, ClassLookup dirtyLookup, List<TypeAdapter> fieldTypeAdapters, List<TypeAdapterProvider> dynamicTypeAdapters) {
this.cleanLookup = cleanLookup;
this.dirtyLookup = dirtyLookup;
this.fieldTypeAdapters = fieldTypeAdapters;
this.dynamicTypeAdapters = dynamicTypeAdapters;
this.generator = new BytecodeFixerJarGenerator();
Expand All @@ -33,8 +40,21 @@ public BytecodeFixerJarGenerator getGenerator() {
}

public Pair<Type, Type> getFieldTypeChange(String owner, String name) {
Map<String, Pair<Type, Type>> fields = this.newFieldTypes.get(owner);
return fields != null ? fields.get(name) : null;
String key = owner + ":" + name;
return fieldTypeChangesCache.computeIfAbsent(key, k -> {
FieldNode cleanField = this.cleanLookup.findField(owner, name).orElse(null);
if (cleanField == null) {
return null;
}
FieldNode dirtyField = this.dirtyLookup.findField(owner, name).orElse(null);
if (dirtyField == null) {
return null;
}
if (!cleanField.desc.equals(dirtyField.desc)) {
return Pair.of(Type.getType(cleanField.desc), Type.getType(dirtyField.desc));
}
return null;
});
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.sinytra.adapter.patch.api.*;
import org.sinytra.adapter.patch.analysis.selector.FieldMatcher;
import org.sinytra.adapter.patch.api.*;
import org.sinytra.adapter.patch.util.AdapterUtil;

import java.util.Collection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer;
import org.sinytra.adapter.patch.api.*;
import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper;
import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle;
import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle;
import org.sinytra.adapter.patch.api.*;
import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper;
import org.sinytra.adapter.patch.util.MethodQualifier;
import org.slf4j.Logger;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.tree.*;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceFieldVisitor;
import org.objectweb.asm.util.TraceMethodVisitor;
import org.sinytra.adapter.patch.analysis.LocalVariableLookup;
import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle;
import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle;
import org.sinytra.adapter.patch.api.MethodContext;
import org.sinytra.adapter.patch.api.MixinConstants;
import org.sinytra.adapter.patch.api.PatchEnvironment;
import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle;
import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.gen.AccessorInfo;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.sinytra.adapter.patch.util.provider;

import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;

import java.util.Optional;
Expand All @@ -14,4 +15,11 @@ default Optional<MethodNode> findMethod(String owner, String name, String desc)
.filter(mtd -> mtd.name.equals(name) && mtd.desc.equals(desc))
.findFirst();
}

default Optional<FieldNode> findField(String owner, String name) {
return getClass(owner).stream()
.flatMap(cls -> cls.fields.stream())
.filter(fd -> fd.name.equals(name))
.findFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper;
import org.sinytra.adapter.patch.fixes.SimpleTypeAdapter;
import org.sinytra.adapter.patch.fixes.TypeAdapter;
import org.sinytra.adapter.patch.util.provider.ClassLookup;

import java.util.List;
import java.util.Map;

public class BytecodeFixerUpperTestFrontend {
private static final List<TypeAdapter> FIELD_TYPE_ADAPTERS = List.of(
Expand All @@ -18,8 +18,8 @@ public class BytecodeFixerUpperTestFrontend {

private final BytecodeFixerUpper bfu;

public BytecodeFixerUpperTestFrontend() {
this.bfu = new BytecodeFixerUpper(Map.of(), FIELD_TYPE_ADAPTERS);
public BytecodeFixerUpperTestFrontend(ClassLookup cleanLookup, ClassLookup dirtyLookup) {
this.bfu = new BytecodeFixerUpper(cleanLookup, dirtyLookup, FIELD_TYPE_ADAPTERS);
}

public BytecodeFixerUpper unwrap() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import org.sinytra.adapter.patch.api.Patch;
import org.sinytra.adapter.patch.api.PatchEnvironment;
import org.sinytra.adapter.patch.api.RefmapHolder;
import org.sinytra.adapter.patch.fixes.FieldTypeUsageTransformer;
import org.sinytra.adapter.patch.transformer.dynfix.DynamicInjectionPointPatch;
import org.sinytra.adapter.patch.util.provider.ClassLookup;
import org.spongepowered.asm.mixin.FabricUtil;

import java.util.List;
Expand All @@ -14,6 +16,7 @@ public class DynamicMixinPatchTest extends MinecraftMixinPatchTest {
private static final List<Patch> DYNAMIC_PATCHES = List.of(
Patch.builder()
.transform(new DynamicInjectionPointPatch())
.transform(new FieldTypeUsageTransformer())
.build()
);

Expand Down Expand Up @@ -204,10 +207,20 @@ void testModifiedWrapOperationTarget2() throws Exception {
);
}

@Test
void testModifiedFieldType() throws Exception {
assertSameField(
"org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin",
"mob"
);
}

@Override
protected LoadResult load(String className, List<String> allowedMethods) throws Exception {
final ClassNode patched = loadClass(className);
patched.methods.removeIf(m -> !allowedMethods.contains(m.name));
ClassLookup cleanLookup = createCleanLookup();
ClassLookup dirtyLookup = createDirtyLookup();
final PatchEnvironment env = PatchEnvironment.create(
new RefmapHolder() {
@Override
Expand All @@ -221,7 +234,7 @@ public void copyEntries(String from, String to) {
},
createCleanLookup(),
createDirtyLookup(),
new BytecodeFixerUpperTestFrontend().unwrap(),
new BytecodeFixerUpperTestFrontend(cleanLookup, dirtyLookup).unwrap(),
FabricUtil.COMPATIBILITY_LATEST
);
DYNAMIC_PATCHES.forEach(p -> p.apply(patched, env));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import org.assertj.core.api.Assertions;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.*;
import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle;
import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle;
import org.sinytra.adapter.patch.api.MixinClassGenerator;
import org.sinytra.adapter.patch.api.MixinConstants;
import org.sinytra.adapter.patch.api.PatchEnvironment;
import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle;
import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle;
import org.sinytra.adapter.patch.util.AdapterUtil;
import org.sinytra.adapter.patch.util.provider.ClassLookup;
import org.sinytra.adapter.patch.util.provider.ZipClassLookup;
Expand All @@ -30,8 +30,7 @@
import java.util.stream.StreamSupport;
import java.util.zip.ZipFile;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;

public abstract class MinecraftMixinPatchTest {
private static final Logger LOGGER = LogUtils.getLogger();
Expand Down Expand Up @@ -93,6 +92,23 @@ protected final void assertSameCode(
Stream.of(assertions).forEach(c -> c.accept(patched, expected, result.env()));
}

protected final void assertSameField(
String className,
String testName
) throws Exception {
final LoadResult result = load(className, List.of(testName));
final FieldNode patched = result.patched.fields
.stream().filter(m -> m.name.equals(testName))
.findFirst().orElseThrow();
final FieldNode expected = result.expected.fields
.stream().filter(m -> m.name.equals(testName + "Expected"))
.findFirst().orElseThrow();

LOGGER.info("Patched field node: \n{}", patched);

assertEquals(patched.desc, expected.desc, "Field types differ");
}

public static class InsnComparator implements Comparator<AbstractInsnNode> {
@Override
public int compare(AbstractInsnNode o1, AbstractInsnNode o2) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.sinytra.adapter.test.mixin;

import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.RangedCrossbowAttackGoal;
import net.minecraft.world.entity.monster.CrossbowAttackMob;
import net.minecraft.world.entity.monster.Monster;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(RangedCrossbowAttackGoal.class)
public abstract class CrossbowAttackGoalMixin<T extends Monster & CrossbowAttackMob> extends Goal {
@Shadow
@Final
private T mob;

@Shadow
@Final
private Mob mobExpected;
}

0 comments on commit 80a5ada

Please sign in to comment.