diff --git a/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java b/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java index 52a08b5..a61d175 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java @@ -7,7 +7,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.MethodContext; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LVTSnapshot.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LVTSnapshot.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/LVTSnapshot.java rename to definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LVTSnapshot.java index d1a104f..5261c2f 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LVTSnapshot.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LVTSnapshot.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.patch.analysis.locals; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; import it.unimi.dsi.fastutil.ints.Int2IntMap; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVarAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java similarity index 75% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVarAnalyzer.java rename to definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java index 4716674..206548b 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVarAnalyzer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java @@ -1,10 +1,15 @@ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.patch.analysis.locals; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; +import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MethodTransform; import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; import org.sinytra.adapter.patch.util.AdapterUtil; @@ -18,6 +23,25 @@ public final class LocalVarAnalyzer { + public record CapturedLocalsInfo(AdapterUtil.CapturedLocals capturedLocals, ParamsDiffSnapshot diff, List availableTypes) {} + + @Nullable + public static CapturedLocalsInfo getCapturedLocals(MethodContext methodContext) { + AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(methodContext.getMixinMethod(), methodContext); + if (capturedLocals == null) { + return null; + } + // Get available local variables at the injection point in the target method + List available = methodContext.getTargetMethodLocals(capturedLocals.target()); + if (available == null) { + return null; + } + List availableTypes = available.stream().map(MethodContext.LocalVariable::type).toList(); + // Compare expected and available params + ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(capturedLocals.expected(), availableTypes); + return new CapturedLocalsInfo(capturedLocals, diff, availableTypes); + } + public static InsnList findInitializerInsns(MethodNode methodNode, int index) { InsnList insns = new InsnList(); outer: @@ -39,7 +63,7 @@ public static InsnList findInitializerInsns(MethodNode methodNode, int index) { public record CapturedLocalsUsage(LocalVariableLookup targetTable, Int2IntMap usageCount, Int2ObjectMap varInsnLists) {} - public record CapturedLocalsTransform(List used, MethodTransform remover) { + public record CapturedLocalsTransform(List used, MethodTransform remover, List usedLocalNodes) { public CapturedLocalsUsage getUsage(AdapterUtil.CapturedLocals capturedLocals) { LocalVariableLookup targetTable = new LocalVariableLookup(capturedLocals.target().methodNode()); Int2ObjectMap varInsnLists = new Int2ObjectOpenHashMap<>(); @@ -57,6 +81,7 @@ public static CapturedLocalsTransform analyzeCapturedLocals(AdapterUtil.Captured int paramLocalStart = capturedLocals.paramLocalStart(); LocalVariableLookup table = capturedLocals.lvt(); List used = new ArrayList<>(); + List usedLocalNodes = new ArrayList<>(); for (AbstractInsnNode insn : methodNode.instructions) { if (insn instanceof VarInsnNode varInsn) { LocalVariableNode node = table.getByIndexOrNull(varInsn.var); @@ -66,6 +91,7 @@ public static CapturedLocalsTransform analyzeCapturedLocals(AdapterUtil.Captured int ordinal = table.getOrdinal(node); if (ordinal >= paramLocalStart && ordinal <= capturedLocals.paramLocalEnd()) { used.add(ordinal - 1); // Subtract 1, which represents the CI param + usedLocalNodes.add(node); } } } @@ -76,7 +102,7 @@ public static CapturedLocalsTransform analyzeCapturedLocals(AdapterUtil.Captured .boxed().sorted(Collections.reverseOrder()) .forEach(b::remove)) .build(); - return new CapturedLocalsTransform(used, remover); + return new CapturedLocalsTransform(used, remover, usedLocalNodes); } public static void findVariableInitializerInsns(MethodNode methodNode, boolean isStatic, int index, Int2ObjectMap varInsnLists, Int2IntMap usageCount) { diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVarRearrangement.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarRearrangement.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVarRearrangement.java rename to definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarRearrangement.java index 0748485..5b38dbe 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVarRearrangement.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarRearrangement.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.patch.analysis.locals; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVariableLookup.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVariableLookup.java rename to definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java index 4046282..0b6fa9d 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/LocalVariableLookup.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.patch.analysis.locals; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodContext.java b/definition/src/main/java/org/sinytra/adapter/patch/api/MethodContext.java index 52e8e4b..6213a94 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodContext.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/api/MethodContext.java @@ -6,7 +6,7 @@ import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.util.MethodQualifier; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/MethodUpgrader.java b/definition/src/main/java/org/sinytra/adapter/patch/fixes/MethodUpgrader.java index a929fd8..c903383 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/MethodUpgrader.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/fixes/MethodUpgrader.java @@ -7,7 +7,7 @@ import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.LocalVarAnalyzer; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.params.SimpleParamsDiffSnapshot; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java index 4fbcf31..bfea98b 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java @@ -7,6 +7,8 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import org.sinytra.adapter.patch.analysis.*; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.*; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java index 0288fb2..f1ca31a 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java @@ -13,8 +13,8 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import org.sinytra.adapter.patch.LVTOffsets; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.params.SimpleParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; @@ -153,27 +153,19 @@ private Patch.Result offsetVariableIndex(ClassNode classNode, MethodNode methodN @Nullable private ParamsDiffSnapshot compareParameters(ClassNode classNode, MethodNode methodNode, MethodContext methodContext) { - AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(methodNode, methodContext); - if (capturedLocals == null) { + LocalVarAnalyzer.CapturedLocalsInfo info = LocalVarAnalyzer.getCapturedLocals(methodContext); + if (info == null) { return null; } - - // Get available local variables at the injection point in the target method - List available = methodContext.getTargetMethodLocals(capturedLocals.target()); - if (available == null) { - return null; - } - List availableTypes = available.stream().map(MethodContext.LocalVariable::type).toList(); - // Compare expected and available params - ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(capturedLocals.expected(), availableTypes); + ParamsDiffSnapshot diff = info.diff(); if (diff.isEmpty()) { - // No changes required return null; } + AdapterUtil.CapturedLocals capturedLocals = info.capturedLocals(); // 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 - SimpleParamsDiffSnapshot rearrange = rearrangeParameters(capturedLocals.expected(), availableTypes); + SimpleParamsDiffSnapshot rearrange = rearrangeParameters(capturedLocals.expected(), info.availableTypes()); if (rearrange == null) { LOGGER.debug(MIXINPATCH, "Tried to replace local variables in mixin method {}.{} using {}", classNode.name, methodNode.name + methodNode.desc, diff.replacements()); return null; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixLocalCaptureUpgrade.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixLocalCaptureUpgrade.java new file mode 100644 index 0000000..9cfe30d --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixLocalCaptureUpgrade.java @@ -0,0 +1,77 @@ +package org.sinytra.adapter.patch.transformer.dynfix; + +import com.mojang.datafixers.util.Pair; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.Patch; +import org.sinytra.adapter.patch.api.PatchAuditTrail; +import org.sinytra.adapter.patch.util.AdapterUtil; + +import java.util.ArrayList; +import java.util.List; + +public class DynFixLocalCaptureUpgrade implements DynamicFixer { + public record Data(AdapterUtil.CapturedLocals capturedLocals, LocalVarAnalyzer.CapturedLocalsTransform transform) {} + + @Override + @Nullable + public DynFixLocalCaptureUpgrade.Data prepare(MethodContext methodContext) { + if (methodContext.findDirtyInjectionTarget() == null) { + return null; + } + MethodNode methodNode = methodContext.getMixinMethod(); + if (!methodContext.capturesLocals()) { + return null; + } + Type[] paramTypes = Type.getArgumentTypes(methodNode.desc); + List> localAnnotations = AdapterUtil.getAnnotatedParameters(methodNode, paramTypes, MixinConstants.LOCAL, Pair::of); + if (!localAnnotations.isEmpty()) { + return null; + } + + LocalVarAnalyzer.CapturedLocalsInfo info = LocalVarAnalyzer.getCapturedLocals(methodContext); + if (info == null || info.diff().isEmpty()) { + return null; + } + + LocalVarAnalyzer.CapturedLocalsTransform transform = LocalVarAnalyzer.analyzeCapturedLocals(info.capturedLocals(), methodNode); + List availableTypes = new ArrayList<>(info.availableTypes()); + for (LocalVariableNode node : transform.usedLocalNodes()) { + Type expected = Type.getType(node.desc); + List available = availableTypes.stream().filter(expected::equals).toList(); + if (available.size() != 1) { + return null; + } + availableTypes.remove(available.getFirst()); + } + + return new Data(info.capturedLocals(), transform); + } + + @Override + @Nullable + public FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchAuditTrail auditTrail, Data data) { + Patch.Result result = data.transform().remover().apply(methodContext); + if (result == Patch.Result.PASS) { + return null; + } + + int start = data.capturedLocals().paramLocalStart(); + Type[] args = Type.getArgumentTypes(methodNode.desc); + + for (int i = start; i < args.length; i++) { + methodNode.visitParameterAnnotation(i, MixinConstants.LOCAL, false); + } + + auditTrail.recordAudit(this, methodContext, "Upgrade captured locals"); + + return FixResult.of(result, PatchAuditTrail.Match.FULL); + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixMethodComparison.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixMethodComparison.java index e89ffc1..7156d42 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixMethodComparison.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixMethodComparison.java @@ -7,7 +7,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; import org.sinytra.adapter.patch.analysis.MethodLabelComparator; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixParameterTypeAdapter.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixParameterTypeAdapter.java index 86255d4..533b96b 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixParameterTypeAdapter.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixParameterTypeAdapter.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicInjectionPointPatch.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicInjectionPointPatch.java index 66c0b7c..d9ca153 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicInjectionPointPatch.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicInjectionPointPatch.java @@ -13,6 +13,9 @@ @SuppressWarnings({"rawtypes", "unchecked"}) public class DynamicInjectionPointPatch implements MethodTransform { private static final Logger LOGGER = LogUtils.getLogger(); + private static final List> PASSIVE = List.of( + new DynFixLocalCaptureUpgrade() + ); private static final List> PREPATCH = List.of( new DynFixResolveAmbigousTarget() ); @@ -28,13 +31,30 @@ public class DynamicInjectionPointPatch implements MethodTransform { @Override public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - if (methodContext.failsDirtyInjectionCheck() && methodContext.findCleanInjectionTarget() != null) { + if (methodContext.findCleanInjectionTarget() == null) { + return Patch.Result.PASS; + } + + PatchAuditTrail auditTrail = context.environment().auditTrail(); + Patch.Result result = Patch.Result.PASS; + + for (DynamicFixer fix : PASSIVE) { + Object data = fix.prepare(methodContext); + if (data != null) { + auditTrail.recordResult(methodContext, PatchAuditTrail.Match.NONE); + DynamicFixer.FixResult fixResult = fix.apply(classNode, methodNode, methodContext, auditTrail, data); + if (fixResult != null) { + auditTrail.recordResult(methodContext, fixResult.match()); + result = result.or(fixResult.result()); + } + } + } + + if (methodContext.failsDirtyInjectionCheck()) { LOGGER.debug(MIXINPATCH, "Considering method {}.{}", classNode.name, methodNode.name); - PatchAuditTrail auditTrail = context.environment().auditTrail(); auditTrail.recordResult(methodContext, PatchAuditTrail.Match.NONE); - Patch.Result result = Patch.Result.PASS; for (DynamicFixer fix : PREPATCH) { Object data = fix.prepare(methodContext); if (data != null) { @@ -55,8 +75,8 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont } } } - return result; } - return Patch.Result.PASS; + + return result; } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ExtractMixin.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ExtractMixin.java index 038f1d2..c5888e5 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ExtractMixin.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ExtractMixin.java @@ -6,8 +6,8 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.LocalVarAnalyzer; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.api.*; import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; import org.sinytra.adapter.patch.util.AdapterUtil; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ModifyMethodParams.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ModifyMethodParams.java index 68e5391..f948b81 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ModifyMethodParams.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/ModifyMethodParams.java @@ -9,8 +9,8 @@ import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; import org.sinytra.adapter.patch.PatchInstance; -import org.sinytra.adapter.patch.analysis.LVTSnapshot; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.params.SimpleParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.api.*; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InjectParameterTransform.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InjectParameterTransform.java index 8e40438..834b0c3 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InjectParameterTransform.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InjectParameterTransform.java @@ -12,7 +12,7 @@ import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.LVTSnapshot; +import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.fixes.ModifyArgsOffsetTransformer; import org.sinytra.adapter.patch.util.AdapterUtil; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InlineParameterTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InlineParameterTransformer.java index 852c235..845c3f3 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InlineParameterTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InlineParameterTransformer.java @@ -7,7 +7,7 @@ import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.analysis.LVTSnapshot; +import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/MoveParametersTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/MoveParametersTransformer.java index 38aaf81..ab0c35a 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/MoveParametersTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/MoveParametersTransformer.java @@ -8,11 +8,11 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.ParameterNode; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.analysis.LVTSnapshot; +import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java index 3ecf40d..fa273cf 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java @@ -8,7 +8,7 @@ import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.analysis.LVTSnapshot; +import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.List; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ReplaceParametersTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ReplaceParametersTransformer.java index f584650..bf59bc0 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ReplaceParametersTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ReplaceParametersTransformer.java @@ -6,7 +6,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SubstituteParameterTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SubstituteParameterTransformer.java index bd7efcf..ffe8aec 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SubstituteParameterTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SubstituteParameterTransformer.java @@ -9,7 +9,7 @@ import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.analysis.LVTSnapshot; +import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/AdapterUtil.java b/definition/src/main/java/org/sinytra/adapter/patch/util/AdapterUtil.java index 3a40fa0..9627b51 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/AdapterUtil.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/util/AdapterUtil.java @@ -11,7 +11,7 @@ import org.objectweb.asm.tree.*; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; -import org.sinytra.adapter.patch.analysis.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.MethodContext; diff --git a/plugin/src/main/java/org/sinytra/adapter/gradle/ClassAnalyzer.java b/plugin/src/main/java/org/sinytra/adapter/gradle/ClassAnalyzer.java index affd06b..b233031 100644 --- a/plugin/src/main/java/org/sinytra/adapter/gradle/ClassAnalyzer.java +++ b/plugin/src/main/java/org/sinytra/adapter/gradle/ClassAnalyzer.java @@ -15,7 +15,7 @@ import org.sinytra.adapter.patch.LVTOffsets; import org.sinytra.adapter.patch.PatchInstance; import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.patch.analysis.LocalVarRearrangement; +import org.sinytra.adapter.patch.analysis.locals.LocalVarRearrangement; import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/DynamicMixinPatchTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/DynamicMixinPatchTest.java index b0de265..00961c0 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/DynamicMixinPatchTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/DynamicMixinPatchTest.java @@ -39,7 +39,8 @@ public String remap(String cls, String reference) { } @Override - public void copyEntries(String from, String to) {} + public void copyEntries(String from, String to) { + } }, cleanLookup, dirtyLookup, @@ -258,6 +259,16 @@ void testDynamicParameterTypeAdapter() throws Exception { ); } + @Test + void testDynamicLocalCaptureupgrade() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mixin/GuiMixin", + "cozyBackground", + assertTargetMethod(), + assertInjectionPoint() + ); + } + @Override protected LoadResult load(String className, List allowedMethods) throws Exception { final ClassNode patched = loadClass(className); diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/MinecraftMixinPatchTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/MinecraftMixinPatchTest.java index 9b26256..0c420af 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/MinecraftMixinPatchTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/MinecraftMixinPatchTest.java @@ -21,6 +21,7 @@ import java.nio.file.Path; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; @@ -89,6 +90,19 @@ protected final void assertSameCode( }) .containsExactlyInAnyOrder(expected.localVariables.toArray(LocalVariableNode[]::new)); + Assertions.assertThat(Objects.requireNonNullElseGet(patched.invisibleParameterAnnotations, () -> new List[0])) + .as("Invisible parameter annotations") + .usingElementComparator(Comparator.comparing(l -> l == null ? "null" : ((List) l).stream().map(a -> a.desc).toList().toString())) + .withRepresentation(object -> { + if (object instanceof List list) { + object = list.toArray(List[]::new); + } + return Stream.of(((List[]) object)) + .map(n -> n == null ? "null" : n.stream().map(o -> o.desc).toList().toString()) + .collect(Collectors.joining("\n ")); + }) + .containsExactlyInAnyOrder(Objects.requireNonNullElseGet(expected.invisibleParameterAnnotations, () -> new List[0])); + Stream.of(assertions).forEach(c -> c.accept(patched, expected, result.env())); } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/GuiMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/GuiMixin.java index 22af369..729d0ec 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/GuiMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/GuiMixin.java @@ -1,9 +1,21 @@ package org.sinytra.adapter.test.mixin; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.client.DeltaTracker; import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.MobEffectTextureManager; +import net.minecraft.core.Holder; +import net.minecraft.world.effect.MobEffectInstance; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.Collection; +import java.util.Iterator; @Mixin(Gui.class) public class GuiMixin { @@ -37,4 +49,35 @@ private int modifyTextureStatusBarsFood(int y) { private int modifyTextureStatusBarsFoodExpected(int y) { return y; } + + // https://github.com/MoriyaShiine/hearty-meals/blob/3b3042e3c2f774987896273623f5f63055401471/src/main/java/moriyashiine/heartymeals/mixin/client/InGameHudMixin.java#L103 + @Inject( + method = "renderEffects(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", + at = @At( + value = "INVOKE_ASSIGN", + target = "Lnet/minecraft/world/effect/MobEffectInstance;getEffect()Lnet/minecraft/core/Holder;", + shift = At.Shift.AFTER + ), + locals = LocalCapture.CAPTURE_FAILHARD + ) + private void cozyBackground(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci, + Collection collection, MobEffectTextureManager statusEffectSpriteManager, Iterator var8, MobEffectInstance statusEffectInstance, Holder registryEntry + ) { + // Use only a single captured local + boolean something = registryEntry == null; + } + + @Inject( + method = "renderEffects(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", + at = @At( + value = "INVOKE_ASSIGN", + target = "Lnet/minecraft/world/effect/MobEffectInstance;getEffect()Lnet/minecraft/core/Holder;", + shift = At.Shift.AFTER + ), + locals = LocalCapture.CAPTURE_FAILHARD + ) + private void cozyBackgroundExpected(GuiGraphics context, DeltaTracker tickCounter, CallbackInfo ci, @Local Holder registryEntry) { + // Use only a single captured local + boolean something = registryEntry == null; + } }