Skip to content

Commit

Permalink
Allow replacing unused params in DynamicLVTPatch
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Jan 26, 2024
1 parent 197a04e commit 41741fe
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ private static Patch.Result recreateLocalVariables(ClassNode classNode, MethodNo
}
}
// Find instructions used to initialize each used variable in the target method
LocalVariableLookup targetTable = new LocalVariableLookup(capturedLocals.target().methodNode().localVariables);
LocalVariableLookup targetTable = new LocalVariableLookup(capturedLocals.target().methodNode());
Int2ObjectMap<InsnList> varInsnLists = new Int2ObjectOpenHashMap<>();
Int2IntMap usageCount = new Int2IntOpenHashMap();
used.forEach(ordinal -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public Result apply(ClassNode classNode, MethodNode methodNode, MethodContext me
methodNode.localVariables.add(paramOrdinal + (isNonStatic ? 1 : 0), new LocalVariableNode(newParameter.name, type.getDescriptor(), null, self.start, self.end, lvtIndex));
snapshot.applyDifference(methodNode);
}
LocalVariableLookup lvtLookup = new LocalVariableLookup(methodNode.localVariables);
LocalVariableLookup lvtLookup = new LocalVariableLookup(methodNode);
BytecodeFixerUpper bfu = context.environment().bytecodeFixerUpper();
this.context.replacements.forEach(pair -> {
int index = pair.getFirst();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public Collection<String> getAcceptedAnnotations() {

@Override
public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) {
LocalVariableLookup lookup = new LocalVariableLookup(methodNode.localVariables);
LocalVariableLookup lookup = new LocalVariableLookup(methodNode);
Type newOwnerType = Type.getType(this.newTarget.owner());
boolean sameOwnerType = Type.getType(this.originalTarget.owner()).equals(newOwnerType);

Expand Down Expand Up @@ -78,7 +78,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont
.build();
addNewParamsPatch.apply(classNode, methodNode, methodContext, context);

LocalVariableLookup updatedLookup = new LocalVariableLookup(methodNode.localVariables);
LocalVariableLookup updatedLookup = new LocalVariableLookup(methodNode);
LocalVariableNode operationVar = updatedLookup.getForType(OPERATION_TYPE).get(0);
int operationParamOrdinal = updatedLookup.getOrdinal(operationVar);
List<LocalVariableNode> localVars = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public OptionalInt getUpdatedOrdinal(PatchContext context, MethodNode methodNode
return OptionalInt.empty();
}

LocalVariableLookup dirtyVarLookup = new LocalVariableLookup(dirtyTarget.methodNode().localVariables);
LocalVariableLookup dirtyVarLookup = new LocalVariableLookup(dirtyTarget.methodNode());
List<LocalVariableNode> dirtyLocals = dirtyVarLookup.getForType(targetType);
if (cleanLocals.size() != dirtyLocals.size() || dirtyLocals.size() <= ordinal) {
return findReplacementLocal(cleanTarget.methodNode(), dirtyTarget.methodNode(), cleanLocal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import dev.su5ed.sinytra.adapter.patch.LVTOffsets;
import dev.su5ed.sinytra.adapter.patch.analysis.EnhancedParamsDiff;
import dev.su5ed.sinytra.adapter.patch.analysis.ParametersDiff;
import dev.su5ed.sinytra.adapter.patch.api.*;
import dev.su5ed.sinytra.adapter.patch.api.MethodContext;
import dev.su5ed.sinytra.adapter.patch.api.MethodTransform;
import dev.su5ed.sinytra.adapter.patch.api.MixinConstants;
import dev.su5ed.sinytra.adapter.patch.api.Patch.Result;
import dev.su5ed.sinytra.adapter.patch.api.PatchContext;
import dev.su5ed.sinytra.adapter.patch.selector.AnnotationHandle;
import dev.su5ed.sinytra.adapter.patch.selector.AnnotationValueHandle;
import dev.su5ed.sinytra.adapter.patch.transformer.ModifyMethodParams;
import dev.su5ed.sinytra.adapter.patch.util.AdapterUtil;
import dev.su5ed.sinytra.adapter.patch.util.LocalVariableLookup;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
Expand All @@ -20,6 +24,7 @@

import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static dev.su5ed.sinytra.adapter.patch.PatchInstance.MIXINPATCH;

Expand Down Expand Up @@ -159,8 +164,8 @@ private ParametersDiff compareParameters(ClassNode classNode, MethodNode methodN
// No changes required
return null;
}
// Replacements are not supported, as they would require LVT fixups and converters
if (!diff.replacements().isEmpty()) {
// Replacements are only partially supported, as most would require LVT fixups and converters
if (!diff.replacements().isEmpty() && areReplacedParamsUsed(diff.replacements(), methodNode)) {
// Check if we can rearrange parameters
ParametersDiff rearrange = ParametersDiff.rearrangeParameters(capturedLocals.expected(), availableTypes);
if (rearrange == null) {
Expand Down Expand Up @@ -198,6 +203,19 @@ private ParametersDiff compareParameters(ClassNode classNode, MethodNode methodN
return offsetDiff;
}

private static boolean areReplacedParamsUsed(List<Pair<Integer, Type>> replacements, MethodNode methodNode) {
LocalVariableLookup lookup = new LocalVariableLookup(methodNode);
Set<Integer> paramLocals = replacements.stream()
.map(p -> lookup.getByParameterOrdinal(p.getFirst()).index)
.collect(Collectors.toSet());
for (AbstractInsnNode insn : methodNode.instructions) {
if (insn instanceof VarInsnNode varInsn && paramLocals.contains(varInsn.var)) {
return true;
}
}
return false;
}

private static int getMaxLocalIndex(List<Type> expected, List<Pair<Integer, Type>> insertions) {
int maxIndex = expected.size();
for (Pair<Integer, Type> pair : insertions) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public static CapturedLocals getCapturedLocals(MethodNode methodNode, MethodCont
int paramLocalPos = targetParams.length + 1;
// Get expected local variables from method parameters
List<Type> expected = AdapterUtil.summariseLocals(params, paramLocalPos);
return new CapturedLocals(target, isStatic, paramLocalPos, paramLocalPos + expected.size(), lvtOffset, expected, new LocalVariableLookup(methodNode.localVariables));
return new CapturedLocals(target, isStatic, paramLocalPos, paramLocalPos + expected.size(), lvtOffset, expected, new LocalVariableLookup(methodNode));
}

public record CapturedLocals(MethodContext.TargetPair target, boolean isStatic, int paramLocalStart, int paramLocalEnd, int lvtOffset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;

import java.util.*;

public class LocalVariableLookup {
private final List<LocalVariableNode> sortedLocals;
private final boolean isNonStatic;
private final Int2ObjectMap<LocalVariableNode> byIndex = new Int2ObjectOpenHashMap<>();
private final Map<Type, List<LocalVariableNode>> byType = new HashMap<>();

public LocalVariableLookup(List<LocalVariableNode> locals) {
this.sortedLocals = locals.stream().sorted(Comparator.comparingInt(lvn -> lvn.index)).toList();
public LocalVariableLookup(MethodNode methodNode) {
this.isNonStatic = (methodNode.access & Opcodes.ACC_STATIC) == 0;
this.sortedLocals = methodNode.localVariables.stream().sorted(Comparator.comparingInt(lvn -> lvn.index)).toList();
for (LocalVariableNode node : this.sortedLocals) {
this.byIndex.put(node.index, node);
}
Expand All @@ -23,6 +27,10 @@ public LocalVariableNode getByOrdinal(int ordinal) {
return this.sortedLocals.get(ordinal);
}

public LocalVariableNode getByParameterOrdinal(int ordinal) {
return this.sortedLocals.get(this.isNonStatic ? ordinal + 1 : ordinal);
}

public LocalVariableNode getByIndex(int index) {
return Objects.requireNonNull(this.byIndex.get(index), "Missing local variable at index " + index);
}
Expand All @@ -34,7 +42,7 @@ public int getOrdinal(LocalVariableNode node) {
public LocalVariableNode getLast() {
return this.sortedLocals.get(this.sortedLocals.size() - 1);
}

public List<LocalVariableNode> getForType(LocalVariableNode node) {
return getForType(Type.getType(node.desc));
}
Expand Down

0 comments on commit 41741fe

Please sign in to comment.