Skip to content

Commit

Permalink
Migrate some usages of ModifyMethodParams to TransformParameters
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Apr 6, 2024
1 parent 3b37e76 commit 5425d60
Show file tree
Hide file tree
Showing 21 changed files with 257 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
import com.google.common.collect.Maps;
import com.mojang.logging.LogUtils;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;
import org.sinytra.adapter.patch.util.GeneratedVariables;
import org.slf4j.Logger;

import java.util.*;
Expand All @@ -29,17 +33,50 @@ public static LayeredParamsDiffSnapshot createLayered(List<Type> clean, List<Typ
return builder.build();
}

public static LayeredParamsDiffSnapshot compareMethodParameters(MethodNode clean, MethodNode dirty) {
if (clean.localVariables == null || dirty.localVariables == null) {
return LayeredParamsDiffSnapshot.EMPTY;
}

int cleanParamCount = Type.getArgumentTypes(clean.desc).length;
int dirtyParamCount = Type.getArgumentTypes(dirty.desc).length;
boolean isCleanStatic = (clean.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC;
boolean isDirtyStatic = (dirty.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC;
// Get params as local variables, which include their names as well
List<LocalVariable> cleanParams = clean.localVariables.stream()
.sorted(Comparator.comparingInt(lv -> lv.index))
.filter(lv -> isCleanStatic || lv.index != 0)
.limit(cleanParamCount)
.map(LocalVariable::new)
.toList();
List<LocalVariable> dirtyParams = dirty.localVariables.stream()
.sorted(Comparator.comparingInt(lv -> lv.index))
.filter(lv -> isDirtyStatic || lv.index != 0)
.limit(dirtyParamCount)
.map(LocalVariable::new)
.toList();
boolean compareNames = cleanParams.stream().allMatch(t -> t.name() != null) && dirtyParams.stream().anyMatch(LocalVariable::isGenerated);

LayeredParamsDiffSnapshot.Builder builder = LayeredParamsDiffSnapshot.builder();
buildDiffWithContext(builder, createPositionedVariableList(cleanParams), createPositionedVariableList(dirtyParams), compareNames);
return builder.build();
}

private static void buildDiff(ParamsDiffSnapshotBuilder builder, List<Type> clean, List<Type> dirty) {
List<TypeWithContext> cleanQueue = createPositionedList(clean);
List<TypeWithContext> dirtyQueue = createPositionedList(dirty);
buildDiffWithContext(builder, createPositionedList(clean), createPositionedList(dirty), false);
}

private static void buildDiffWithContext(ParamsDiffSnapshotBuilder builder, List<TypeWithContext> cleanQueue, List<TypeWithContext> dirtyQueue, boolean compareNames) {
int dirtySize = dirtyQueue.size();

if (DEBUG) {
LOGGER.info("Comparing types:\n{}", printTable(cleanQueue, dirtyQueue));
}

while (!cleanQueue.isEmpty()) {
// Look ahead for matching types at the beginning of the list
// If the first two are equal, remove the first ones and repeat
if (cleanQueue.size() > 1 && dirtyQueue.size() > 1 && cleanQueue.get(0).sameType(dirtyQueue.get(0)) && cleanQueue.get(1).sameType(dirtyQueue.get(1))) {
if (sameParameter(cleanQueue, dirtyQueue, compareNames)) {
cleanQueue.remove(0);
dirtyQueue.remove(0);
continue;
Expand All @@ -57,10 +94,11 @@ private static void buildDiff(ParamsDiffSnapshotBuilder builder, List<Type> clea
break;
}
// Find the smallest set of matching types by locating the position of the next clean type in the dirty list
int dirtyTypeIndex = cleanQueue.size() == 1 ? dirty.size() - 1 : lookAhead(dirtyQueue, cleanQueue.get(1));
int dirtyTypeIndex = cleanQueue.size() == 1 ? dirtySize - 1 : lookAhead(dirtyQueue, cleanQueue.get(1));
if (dirtyTypeIndex != -1) {
int offset = cleanQueue.get(0).sameType(dirtyQueue.get(0)) ? 1 : 2;
List<TypeWithContext> compareClean = extract(cleanQueue, 2);
boolean matchesName = !compareNames || cleanQueue.size() < 2 || dirtyQueue.size() < 2 || cleanQueue.get(1).matches(dirtyQueue.get(1));
int offset = cleanQueue.get(0).sameType(dirtyQueue.get(0)) && matchesName ? 1 : 2;
List<TypeWithContext> compareClean = extract(cleanQueue, matchesName ? 2 : 1);
List<TypeWithContext> compareDirty = extract(dirtyQueue, dirtyTypeIndex + offset);

compare(builder, compareClean, compareDirty);
Expand Down Expand Up @@ -89,6 +127,13 @@ else if (cleanQueue.size() == dirtyQueue.size() && (dirtyTypeIndex = findClosest
}
}

private static boolean sameParameter(List<TypeWithContext> cleanQueue, List<TypeWithContext> dirtyQueue, boolean compareNames) {
return cleanQueue.size() > 1 && dirtyQueue.size() > 1 && (
compareNames ? cleanQueue.get(0).matches(dirtyQueue.get(0)) && cleanQueue.get(1).matches(dirtyQueue.get(1))
: cleanQueue.get(0).sameType(dirtyQueue.get(0)) && cleanQueue.get(1).sameType(dirtyQueue.get(1))
);
}

private static int findClosestMatch(List<TypeWithContext> cleanQueue, List<TypeWithContext> dirtyQueue) {
for (TypeWithContext typeWithContext : cleanQueue) {
int pos = lookAhead(dirtyQueue, typeWithContext);
Expand Down Expand Up @@ -131,7 +176,8 @@ private static boolean isPossiblyInjected(int index, List<TypeWithContext> clean
return false;
}

private record SwapResult(List<TypeWithContext> removeDirty) {}
private record SwapResult(List<TypeWithContext> removeDirty) {
}

@Nullable
private static SwapResult checkForSwaps(ParamsDiffSnapshotBuilder builder, List<TypeWithContext> clean, List<TypeWithContext> dirty) {
Expand Down Expand Up @@ -249,9 +295,9 @@ private static void compare(ParamsDiffSnapshotBuilder builder, List<TypeWithCont
LOGGER.info("Running comparison for:\n{}", printTable(clean, dirty));
}

Type[] cleanTypes = clean.stream().map(TypeWithContext::type).toArray(Type[]::new);
Type[] dirtyTypes = dirty.stream().map(TypeWithContext::type).toArray(Type[]::new);
ParametersDiff diff = ParametersDiff.compareTypeParameters(cleanTypes, dirtyTypes);
List<ParametersDiff.MethodParameter> cleanTypes = clean.stream().map(t -> new ParametersDiff.MethodParameter(t.type(), t.isGenerated())).toList();
List<ParametersDiff.MethodParameter> dirtyTypes = dirty.stream().map(t -> new ParametersDiff.MethodParameter(t.type(), t.isGenerated())).toList();
ParametersDiff diff = ParametersDiff.compareParameters(cleanTypes, dirtyTypes, false);
if (DEBUG) {
LOGGER.info("Comparison results:\n\tInserted: {}\n\tReplaced: {}\n\tSwapped: {}\n\tRemoved: {}", diff.insertions(), diff.removals(), diff.swaps(), diff.removals());
}
Expand All @@ -267,6 +313,15 @@ private static List<TypeWithContext> createPositionedList(List<Type> list) {
return ret;
}

private static List<TypeWithContext> createPositionedVariableList(List<LocalVariable> list) {
List<TypeWithContext> ret = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
LocalVariable ctx = list.get(i);
ret.add(new TypeWithContext(ctx.name(), ctx.type(), i, ctx.isGenerated()));
}
return ret;
}

private static boolean sameTypeCount(Map<Type, Integer> cleanGroup, Map<Type, Integer> dirtyGroup) {
if (cleanGroup.size() != dirtyGroup.size()) {
return false;
Expand Down Expand Up @@ -320,9 +375,27 @@ private static String printTable(List<TypeWithContext> clean, List<TypeWithConte
return builder.toString();
}

private record TypeWithContext(Type type, int pos) {
private record LocalVariable(@Nullable String name, Type type, boolean isGenerated) {
public LocalVariable(LocalVariableNode lvn) {
this(lvn.name, Type.getType(lvn.desc), lvn.name != null && GeneratedVariables.isGeneratedVariableName(lvn.name, Type.getType(lvn.desc)));
}
}

private record TypeWithContext(@Nullable String name, Type type, int pos, boolean isGenerated) {
public TypeWithContext(Type type, int pos) {
this(null, type, pos, false);
}

public boolean sameType(TypeWithContext other) {
return type().equals(other.type());
}

public boolean sameName(TypeWithContext other) {
return this.name == null || other.name() == null || this.isGenerated == other.isGenerated();
}

public boolean matches(TypeWithContext other) {
return sameType(other) && sameName(other);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.util.function.Consumer;

public record LayeredParamsDiffSnapshot(List<ParamModification> modifications) implements ParamsDiffSnapshot {
public static LayeredParamsDiffSnapshot EMPTY = new LayeredParamsDiffSnapshot(List.of());

interface ParamModification {
ParamModification offset(int offset);

Expand Down Expand Up @@ -164,6 +166,22 @@ public List<Pair<Integer, Type>> replacements() {
.toList();
}

public List<Pair<Integer, Integer>> swaps() {
return this.modifications.stream()
.map(p -> p instanceof SwapParam param ? param : null)
.filter(Objects::nonNull)
.map(p -> Pair.of(p.from(), p.to()))
.toList();
}

public List<Pair<Integer, Integer>> moves() {
return this.modifications.stream()
.map(p -> p instanceof MoveParam param ? param : null)
.filter(Objects::nonNull)
.map(p -> Pair.of(p.from(), p.to()))
.toList();
}

@Override
public List<Integer> removals() {
return this.modifications.stream()
Expand All @@ -178,9 +196,9 @@ public LayeredParamsDiffSnapshot offset(int offset, int limit) {
}

@Override
public List<MethodTransform> asParameterTransformer(ParamTransformTarget type, boolean withOffset) {
public MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset) {
List<ParameterTransformer> transformers = this.modifications.stream().map(ParamModification::asParameterTransformer).toList();
return List.of(new TransformParameters(transformers, withOffset, type));
return new TransformParameters(transformers, withOffset, type);
}

public static Builder builder() {
Expand All @@ -195,97 +213,97 @@ private Builder() {
}

@Override
public ParamsDiffSnapshotBuilder insert(int index, Type type) {
public Builder insert(int index, Type type) {
this.modifications.add(new InsertParam(index, type));
return this;
}

@Override
public ParamsDiffSnapshotBuilder insertions(List<Pair<Integer, Type>> insertions) {
public Builder insertions(List<Pair<Integer, Type>> insertions) {
insertions.forEach(p -> insert(p.getFirst(), p.getSecond()));
return this;
}

@Override
public ParamsDiffSnapshotBuilder replace(int index, Type type) {
public Builder replace(int index, Type type) {
this.modifications.add(new ReplaceParam(index, type));
return this;
}

@Override
public ParamsDiffSnapshotBuilder replacements(List<Pair<Integer, Type>> replacements) {
public Builder replacements(List<Pair<Integer, Type>> replacements) {
replacements.forEach(p -> replace(p.getFirst(), p.getSecond()));
return this;
}

@Override
public ParamsDiffSnapshotBuilder swap(int from, int to) {
public Builder swap(int from, int to) {
this.modifications.add(new SwapParam(from, to));
return this;
}

@Override
public ParamsDiffSnapshotBuilder swaps(List<Pair<Integer, Integer>> swaps) {
public Builder swaps(List<Pair<Integer, Integer>> swaps) {
swaps.forEach(p -> swap(p.getFirst(), p.getSecond()));
return this;
}

@Override
public ParamsDiffSnapshotBuilder substitute(int target, int substitute) {
public Builder substitute(int target, int substitute) {
this.modifications.add(new SubstituteParam(target, substitute));
return this;
}

@Override
public ParamsDiffSnapshotBuilder substitutes(List<Pair<Integer, Integer>> substitutes) {
public Builder substitutes(List<Pair<Integer, Integer>> substitutes) {
substitutes.forEach(p -> substitute(p.getFirst(), p.getSecond()));
return this;
}

@Override
public ParamsDiffSnapshotBuilder move(int from, int to) {
public Builder move(int from, int to) {
this.modifications.add(new MoveParam(from, to));
return this;
}

@Override
public ParamsDiffSnapshotBuilder moves(List<Pair<Integer, Integer>> moves) {
public Builder moves(List<Pair<Integer, Integer>> moves) {
moves.forEach(p -> move(p.getFirst(), p.getSecond()));
return this;
}

@Override
public ParamsDiffSnapshotBuilder remove(int index) {
public Builder remove(int index) {
this.modifications.add(new RemoveParam(index));
this.removals.add(index);
return this;
}

@Override
public ParamsDiffSnapshotBuilder removals(List<Integer> removals) {
public Builder removals(List<Integer> removals) {
removals.forEach(this::remove);
return this;
}

@Override
public ParamsDiffSnapshotBuilder inline(int target, Consumer<InstructionAdapter> adapter) {
public Builder inline(int target, Consumer<InstructionAdapter> adapter) {
this.modifications.add(new InlineParam(target, adapter));
return this;
}

@Override
public ParamsDiffSnapshotBuilder inlines(List<Pair<Integer, Consumer<InstructionAdapter>>> inlines) {
public Builder inlines(List<Pair<Integer, Consumer<InstructionAdapter>>> inlines) {
inlines.forEach(p -> inline(p.getFirst(), p.getSecond()));
return this;
}

@Override
public ParamsDiffSnapshotBuilder merge(SimpleParamsDiffSnapshot diff) {
public Builder merge(SimpleParamsDiffSnapshot diff) {
return merge(diff, 0);
}

@Override
public ParamsDiffSnapshotBuilder merge(SimpleParamsDiffSnapshot diff, int indexOffset) {
public Builder merge(SimpleParamsDiffSnapshot diff, int indexOffset) {
diff.insertions().forEach(p -> insert(p.getFirst() + indexOffset, p.getSecond()));
diff.replacements().forEach(p -> replace(p.getFirst() + indexOffset, p.getSecond()));
diff.swaps().forEach(p -> swap(p.getFirst() + indexOffset, p.getSecond() + indexOffset));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ public interface ParamsDiffSnapshot {

ParamsDiffSnapshot offset(int offset, int limit);

List<MethodTransform> asParameterTransformer(ParamTransformTarget type, boolean withOffset);
MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import org.sinytra.adapter.patch.api.MethodTransform;
import org.sinytra.adapter.patch.transformer.BundledMethodTransform;
import org.sinytra.adapter.patch.transformer.ModifyMethodParams;
import org.sinytra.adapter.patch.transformer.param.InjectParameterTransform;
import org.sinytra.adapter.patch.transformer.param.ParamTransformTarget;
Expand Down Expand Up @@ -87,7 +88,7 @@ public SimpleParamsDiffSnapshot offset(int offset, int limit) {
}

@Override
public List<MethodTransform> asParameterTransformer(ParamTransformTarget type, boolean withOffset) {
public MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset) {
List<MethodTransform> list = new ArrayList<>();
SimpleParamsDiffSnapshot light = new SimpleParamsDiffSnapshot(List.of(), this.replacements, this.swaps, this.substitutes, this.removals, this.moves, this.inlines);
if (!light.isEmpty()) {
Expand All @@ -98,7 +99,7 @@ public List<MethodTransform> asParameterTransformer(ParamTransformTarget type, b
.<ParameterTransformer>map(p -> new InjectParameterTransform(p.getFirst(), p.getSecond()))
.toList(), true, type));
}
return list;
return new BundledMethodTransform(list);
}

public static Builder builder() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff;
import org.sinytra.adapter.patch.analysis.params.SimpleParamsDiffSnapshot;
import org.sinytra.adapter.patch.api.MethodContext;
import org.sinytra.adapter.patch.api.MethodTransform;
import org.sinytra.adapter.patch.api.MixinConstants;
import org.sinytra.adapter.patch.transformer.ModifyArgsOffsetTransformer;
import org.sinytra.adapter.patch.transformer.ModifyMethodParams;
import org.sinytra.adapter.patch.transformer.param.ParamTransformTarget;
import org.sinytra.adapter.patch.util.MethodQualifier;

Expand Down Expand Up @@ -51,7 +51,7 @@ private static void upgradeWrapOperation(ClassNode classNode, MethodNode methodN
// Create diff
SimpleParamsDiffSnapshot diff = EnhancedParamsDiff.create(originalDesc, modifiedDesc);
if (!diff.isEmpty()) {
ModifyMethodParams patch = ModifyMethodParams.create(diff, ParamTransformTarget.ALL);
MethodTransform patch = diff.asParameterTransformer(ParamTransformTarget.ALL, true);
patch.apply(classNode, methodNode, methodContext, methodContext.patchContext());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.sinytra.adapter.patch.transformer;

import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.sinytra.adapter.patch.api.MethodContext;
import org.sinytra.adapter.patch.api.MethodTransform;
import org.sinytra.adapter.patch.api.Patch;
import org.sinytra.adapter.patch.api.PatchContext;

import java.util.List;

public record BundledMethodTransform(List<MethodTransform> transforms) implements MethodTransform {
@Override
public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) {
Patch.Result result = Patch.Result.PASS;
for (MethodTransform transform : this.transforms) {
result = result.or(transform.apply(classNode, methodNode, methodContext, context));
}
return result;
}
}
Loading

0 comments on commit 5425d60

Please sign in to comment.