From 469839c481bd57176b413c174b657d9b3fffbf03 Mon Sep 17 00:00:00 2001 From: Matyrobbrt Date: Thu, 25 Jan 2024 21:08:55 +0200 Subject: [PATCH] Remove param transformer --- .../param/ParameterTransformer.java | 24 ++++++++-- .../param/RemoveParameterTransformer.java | 44 +++++++++++++++++++ .../param/TransformParameters.java | 9 ++++ .../patch/test/mixin/ParameterRemoveTest.java | 31 +++++++++++++ .../adapter/test/classes/ParameterRemove.java | 19 ++++++++ .../test/mixins/ParameterInlineMixin.java | 8 ++-- .../test/mixins/ParameterRemoveMixin.java | 31 +++++++++++++ 7 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/RemoveParameterTransformer.java create mode 100644 definition/src/test/java/dev/su5ed/sinytra/adapter/patch/test/mixin/ParameterRemoveTest.java create mode 100644 definition/src/testClasses/java/org/sinytra/adapter/test/classes/ParameterRemove.java create mode 100644 definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterRemoveMixin.java diff --git a/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/ParameterTransformer.java b/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/ParameterTransformer.java index ae7f921..585b993 100644 --- a/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/ParameterTransformer.java +++ b/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/ParameterTransformer.java @@ -78,7 +78,7 @@ default void extractWrapOperation(final MethodContext methodContext, final Metho // Assume that people are only calling `call` on the operation object if (!( AdapterUtil.getIntConstValue(methodNode.instructions.get(loadInsnIndex + 1)).isPresent() && - methodNode.instructions.get(loadInsnIndex + 2) instanceof TypeInsnNode n && n.getOpcode() == Opcodes.ANEWARRAY + methodNode.instructions.get(loadInsnIndex + 2) instanceof TypeInsnNode n && n.getOpcode() == Opcodes.ANEWARRAY )) { return; } @@ -203,10 +203,24 @@ public void removeParameter(int index) { methodNode.instructions.set(methodNode.instructions.get(methodNode.instructions.indexOf(objects[j - 1].get(0)) - 1), AdapterUtil.getIntConstInsn(j - 1)); } } - methodNode.instructions.remove(methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.get(0)) - 1)); - methodNode.instructions.remove(methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.get(toRemove.size() - 1)) + 1)); - methodNode.instructions.remove(methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.get(toRemove.size() - 1)) + 2)); + + final AbstractInsnNode dup = methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.get(toRemove.size() - 1)) + 2); + List.of( + methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.get(0)) - 1), + methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.get(toRemove.size() - 1)) + 1) + ).forEach(methodNode.instructions::remove); toRemove.forEach(methodNode.instructions::remove); + if (dup.getOpcode() == Opcodes.DUP) { + methodNode.instructions.remove(dup); + } + + if (position > 0 && !objects[position - 1].isEmpty()) { + // Make sure that the last one doesn't have a DUP + final int lastOfPrevious = methodNode.instructions.indexOf(objects[position - 1].get(objects[position - 1].size() - 1)); + if (methodNode.instructions.get(lastOfPrevious + 2).getOpcode() == Opcodes.DUP) { + methodNode.instructions.remove(methodNode.instructions.get(lastOfPrevious + 2)); + } + } }); // Continue from the new position of the call @@ -230,7 +244,9 @@ default Codec codec() { interface WrapOpModification { void insertParameter(int index, Consumer adapter); + void replaceParameter(int index, Consumer adapter); + void removeParameter(int index); } } diff --git a/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/RemoveParameterTransformer.java b/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/RemoveParameterTransformer.java new file mode 100644 index 0000000..bd14e4c --- /dev/null +++ b/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/RemoveParameterTransformer.java @@ -0,0 +1,44 @@ +package dev.su5ed.sinytra.adapter.patch.transformer.param; + +import com.mojang.serialization.Codec; +import dev.su5ed.sinytra.adapter.patch.api.MethodContext; +import dev.su5ed.sinytra.adapter.patch.api.Patch; +import dev.su5ed.sinytra.adapter.patch.api.PatchContext; +import dev.su5ed.sinytra.adapter.patch.util.AdapterUtil; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodNode; + +import java.util.List; + +public record RemoveParameterTransformer(int index) implements ParameterTransformer { + public static final Codec CODEC = Codec.intRange(0, 255) + .fieldOf("index").xmap(RemoveParameterTransformer::new, RemoveParameterTransformer::index) + .codec(); + + @Override + public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + final int target = this.index() + offset; + final int lvtIndex = ParameterTransformer.calculateLVTIndex(parameters, !methodContext.isStatic(methodNode), target); + + // Remove the use of the param in a wrapop first to avoid the new LVT messing with the outcome of that + extractWrapOperation(methodContext, methodNode, parameters, op -> op.removeParameter(target)); + + withLVTSnapshot(methodNode, () -> { + LocalVariableNode lvn = methodNode.localVariables.stream() + .filter(v -> v.index == lvtIndex) + .findFirst() + .orElse(null); + if (lvn != null) { + methodNode.localVariables.remove(lvn); + AdapterUtil.replaceLVT(methodNode, idx -> idx == lvtIndex ? -1 : idx); + } + }); + + methodNode.parameters.remove(target); + parameters.remove(target); + + return Patch.Result.COMPUTE_FRAMES; + } +} diff --git a/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/TransformParameters.java b/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/TransformParameters.java index 15d566a..18b0585 100644 --- a/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/TransformParameters.java +++ b/definition/src/main/java/dev/su5ed/sinytra/adapter/patch/transformer/param/TransformParameters.java @@ -2,6 +2,8 @@ import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.CheckReturnValue; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import dev.su5ed.sinytra.adapter.patch.api.MethodContext; @@ -25,6 +27,7 @@ public record TransformParameters(List transformers, boole .put("inject_parameter", InjectParameterTransform.CODEC) .put("swap_parameters", SwapParametersTransformer.CODEC) .put("substitute_parameters", SubstituteParameterTransformer.CODEC) + .put("remove_parameter", RemoveParameterTransformer.CODEC) .build(); public static final Codec CODEC = RecordCodecBuilder.create(in -> in.group( @@ -62,6 +65,7 @@ public Codec codec() { return CODEC; } + @CanIgnoreReturnValue public static class Builder { private final List transformers = new ArrayList<>(); private boolean offset = false; @@ -87,11 +91,16 @@ public Builder inline(int target, Consumer adapter) { return this.transform(new InlineParameterTransformer(target, adapter)); } + public Builder remove(int index) { + return this.transform(new RemoveParameterTransformer(index)); + } + public Builder withOffset() { this.offset = true; return this; } + @CheckReturnValue public TransformParameters build() { return new TransformParameters(transformers, offset); } diff --git a/definition/src/test/java/dev/su5ed/sinytra/adapter/patch/test/mixin/ParameterRemoveTest.java b/definition/src/test/java/dev/su5ed/sinytra/adapter/patch/test/mixin/ParameterRemoveTest.java new file mode 100644 index 0000000..a199ebf --- /dev/null +++ b/definition/src/test/java/dev/su5ed/sinytra/adapter/patch/test/mixin/ParameterRemoveTest.java @@ -0,0 +1,31 @@ +package dev.su5ed.sinytra.adapter.patch.test.mixin; + +import dev.su5ed.sinytra.adapter.patch.api.MixinConstants; +import dev.su5ed.sinytra.adapter.patch.api.Patch; +import org.junit.jupiter.api.Test; + +public class ParameterRemoveTest extends MixinPatchTest { + @Test + void testSimpleRemove() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mixins/ParameterRemoveMixin", + "testSimpleRemove", + Patch.builder() + .targetInjectionPoint("") + .targetMethod("testSimple") + .targetMixinType(MixinConstants.INJECT) + .transformParams(params -> params.remove(2)) + ); + } + + @Test + void testWrapOpRemove() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mixins/ParameterRemoveMixin", + "testWrapOpRemove", + Patch.builder() + .targetMethod("testWrapOp") + .transformParams(params -> params.remove(2)) + ); + } +} diff --git a/definition/src/testClasses/java/org/sinytra/adapter/test/classes/ParameterRemove.java b/definition/src/testClasses/java/org/sinytra/adapter/test/classes/ParameterRemove.java new file mode 100644 index 0000000..48eefc9 --- /dev/null +++ b/definition/src/testClasses/java/org/sinytra/adapter/test/classes/ParameterRemove.java @@ -0,0 +1,19 @@ +package org.sinytra.adapter.test.classes; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class ParameterRemove { + public static void testSimple(int p1, char p2) { + + } + + public static void testWrapOp(SObj sObj, AtomicBoolean p1) { + + } + + public record SObj() { + public void call(AtomicBoolean value) { + + } + } +} diff --git a/definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterInlineMixin.java b/definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterInlineMixin.java index ea2c614..6e1ee85 100644 --- a/definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterInlineMixin.java +++ b/definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterInlineMixin.java @@ -8,21 +8,21 @@ @Mixin(ParameterInline.class) public class ParameterInlineMixin { @Inject(method = "simple(ILjava/lang/String;ILjava/lang/String;)V", at = @At("HEAD")) - private void testSimpleInline(int p1, String p2, int p3, String p4) { + private static void testSimpleInline(int p1, String p2, int p3, String p4) { System.out.println(p4); } - private void testSimpleInlineExpected(int p1, String p2, int p3) { + private static void testSimpleInlineExpected(int p1, String p2, int p3) { System.out.println("inlined"); } @Inject(method = "big(IDI)V", at = @At("HEAD")) - private void testBigInline(int p1, double p2, double p3, int p4) { + private static void testBigInline(int p1, double p2, double p3, int p4) { System.out.println(p3 * p2); System.out.println("p4: " + p4); } - private void testBigInlineExpected(int p1, double p2, int p4) { + private static void testBigInlineExpected(int p1, double p2, int p4) { System.out.println(43d * p2); System.out.println("p4: " + p4); } diff --git a/definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterRemoveMixin.java b/definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterRemoveMixin.java new file mode 100644 index 0000000..f3e8efb --- /dev/null +++ b/definition/src/testClasses/java/org/sinytra/adapter/test/mixins/ParameterRemoveMixin.java @@ -0,0 +1,31 @@ +package org.sinytra.adapter.test.mixins; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import org.sinytra.adapter.test.classes.ParameterRemove; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; + +import java.util.concurrent.atomic.AtomicBoolean; + +@Mixin(ParameterRemove.class) +public class ParameterRemoveMixin { + @Inject(method = "testSimple(IC)V", at = @At("HEAD")) + private static void testSimpleRemove(int p1, char p2, boolean p3) { + System.out.println("Hi: " + p2 / p1); + } + + private static void testSimpleRemoveExpected(int p1, char p2) { + System.out.println("Hi: " + p2 / p1); + } + + @WrapOperation(method = "testWrapOp(Lorg/sinytra/adapter/test/classes/ParameterRemove$SObj;Ljava/util/concurrent/atomic/AtomicBoolean;)V", at = @At(value = "INVOKE", target = "Lorg/sinytra/adapter/test/classes/ParameterRemove$SObj;call(Ljava/util/concurrent/atomic/AtomicBoolean;)V")) + private static void testWrapOpRemove(ParameterRemove.SObj obj, AtomicBoolean p1, int p2, Operation operation) { + System.out.println(operation.call(obj, p1, p2)); + } + + private static void testWrapOpRemoveExpected(ParameterRemove.SObj obj, AtomicBoolean p1, Operation operation) { + System.out.println(operation.call(obj, p1)); + } +}