From d7fbe2f7680146d95ffab77dd7239ee8182e0453 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Fri, 26 Dec 2025 21:44:39 +0100 Subject: [PATCH 01/27] Migrate DynFixSliceBoundary to pipeline --- .../adapter/patch/MethodContextImpl.java | 35 ++++++ .../adapter/patch/api/MethodContext.java | 2 + .../adapter/patch/api/MixinConstants.java | 1 + .../dynfix/DynFixSliceBoundary.java | 106 ------------------ .../dynfix/DynamicInjectionPointPatch.java | 1 - .../next/PipelineLegacyMethodTransformer.java | 4 +- .../sinytra/adapter/next/env/ann/AtData.java | 18 +++ .../env/ann/MixinAnnotationConstants.java | 6 + .../next/env/ann/ModifyVariableMixinData.java | 11 +- .../adapter/next/env/ann/SliceData.java | 35 +++++- .../adapter/next/env/ctx/MethodHelper.java | 3 +- .../next/pipeline/config/Configuration.java | 2 + .../pipeline/config/ConfigurationImpl.java | 15 ++- .../pipeline/config/MutableConfiguration.java | 3 +- ...rocessor.java => ParametersProcessor.java} | 2 +- .../next/pipeline/processor/Processors.java | 2 +- .../pipeline/processor/PropertyProcessor.java | 5 + .../next/pipeline/resolver/Resolvers.java | 2 + .../special/SliceBoundaryResolver.java | 98 ++++++++++++++++ .../adapter/next/type/InjectMixin.java | 5 +- .../next/type/ModifyVariableMixin.java | 13 ++- .../adapter/test/mixin/LivingEntityMixin.java | 4 +- 22 files changed, 249 insertions(+), 124 deletions(-) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixSliceBoundary.java rename definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/{MixinMethodParametersProcessor.java => ParametersProcessor.java} (95%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java 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 f8e16beb..c9022d53 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java @@ -251,6 +251,41 @@ public boolean isNotRequired() { .orElse(false); } + @Override + public boolean hasValidSlice(TargetPair target) { + if (target == null) { + return false; + } + + AnnotationHandle ann = this.methodAnnotation.getValue("slice") + .map(handle -> { + Object value = handle.get(); + return value instanceof List list ? (AnnotationNode) list.getFirst() : (AnnotationNode) value; + }) + .map(AnnotationHandle::new) + .orElse(null); + if (ann == null) { + return true; + } + + AnnotationNode from = ann.getNested("from").map(AnnotationHandle::unwrap).orElse(null); + if (from != null && !validateAtNode(from, target)) { + return false; + } + + AnnotationNode to = ann.getNested("to").map(AnnotationHandle::unwrap).orElse(null); + return to == null || validateAtNode(to, target); + } + + private boolean validateAtNode(AnnotationNode at, TargetPair target) { + List insns = computeInjectionTargetInsns( + target, + this::injectionPointAnnotation, + (ctx, h) -> InjectionPoint.parse(ctx, this.methodNode, methodAnnotation().unwrap(), at) + ); + return !insns.isEmpty(); + } + @Override public void recordAudit(Object transform, String message, Object... args) { this.patchContext.environment().auditTrail().recordAudit(transform, this, message, args); 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 56b51bf2..4929d05f 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 @@ -86,6 +86,8 @@ default List getTargetMethodLocals(TargetPair target, int startPo boolean isNotRequired(); + boolean hasValidSlice(TargetPair target); + void recordAudit(Object transform, String message, Object... args); record LocalVariable(int index, Type type) {} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java b/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java index 77eeefc2..51c28a54 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java @@ -35,6 +35,7 @@ public class MixinConstants { public static final String SHADOW = "Lorg/spongepowered/asm/mixin/Shadow;"; public static final String COERCE = "Lorg/spongepowered/asm/mixin/injection/Coerce;"; public static final String CONSTANT = "Lorg/spongepowered/asm/mixin/injection/Constant;"; + public static final String SLICE = "Lorg/spongepowered/asm/mixin/injection/Slice;"; public static final List LVT_COMPATIBILITY_LEVELS = List.of(FabricUtil.COMPATIBILITY_0_10_0, FabricUtil.COMPATIBILITY_0_9_2); public static final String DEPRECATED = "Ljava/lang/Deprecated;"; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixSliceBoundary.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixSliceBoundary.java deleted file mode 100644 index 262d9b67..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixSliceBoundary.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynfix; - -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Type; -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.MethodContext; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.api.PatchAuditTrail; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.MockMixinRuntime; -import org.spongepowered.asm.mixin.injection.code.ISliceContext; -import org.spongepowered.asm.mixin.injection.code.MethodSlice; -import org.spongepowered.asm.mixin.injection.struct.Target; -import org.spongepowered.asm.mixin.refmap.IMixinContext; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; - -public class DynFixSliceBoundary implements DynamicFixer { - public record Data(AnnotationHandle slice, List slices) {} - - @Nullable - @Override - public DynFixSliceBoundary.Data prepare(MethodContext methodContext) { - MethodContext.TargetPair dirtyTarget = methodContext.findDirtyInjectionTarget(); - if (dirtyTarget == null) { - return null; - } - AnnotationHandle sliceAnnotation = methodContext.methodAnnotation().getNested("slice").orElse(null); - if (sliceAnnotation == null) { - return null; - } - if (passesSliceCheck(sliceAnnotation, methodContext)) { - return null; - } - List slices = Stream.of("from", "to").flatMap(s -> sliceAnnotation.getNested(s).stream()).toList(); - return new Data(sliceAnnotation, slices); - } - - @Override - @Nullable - public FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchAuditTrail auditTrail, Data data) { - MethodContext.TargetPair dirtyTarget = methodContext.findDirtyInjectionTarget(); - Target mixinTarget = MockMixinRuntime.createMixinTarget(dirtyTarget); - AnnotationHandle slice = data.slice(); - - IMixinContext mixinContext = MockMixinRuntime.forClass(classNode.name, dirtyTarget.classNode().name, methodContext.patchContext().environment()); - ISliceContext sliceContext = MockMixinRuntime.forSlice(mixinContext, methodNode); - MethodSlice methodSlice = MethodSlice.parse(sliceContext, slice.unwrap()); - InsnList insns = methodSlice.getSlice(mixinTarget); - - if (insns.size() != dirtyTarget.methodNode().instructions.size()) { - return null; - } - - return FixResult.of(data.slices().stream() - .reduce(Patch.Result.PASS, (a, b) -> a.or(fixSlideInjectionPoint(b, dirtyTarget.methodNode())), Patch.Result::or), PatchAuditTrail.Match.FULL); - } - - private static Patch.Result fixSlideInjectionPoint(AnnotationHandle annotation, MethodNode dirtyMethod) { - // Require only INVOKE values - if (!annotation.getValue("value").map(AnnotationValueHandle::get).map("INVOKE"::equals).orElse(false)) { - return Patch.Result.PASS; - } - // Find original target invocation qualifier - AnnotationValueHandle targetHandle = annotation.getValue("target").orElse(null); - if (targetHandle == null) { - return Patch.Result.PASS; - } - MethodQualifier target = MethodQualifier.create(targetHandle.get()).orElse(null); - if (target == null) { - return Patch.Result.PASS; - } - // Find method invocations with a matching name - List candidates = new ArrayList<>(); - for (AbstractInsnNode insn : dirtyMethod.instructions) { - if (insn instanceof MethodInsnNode minsn && minsn.name.equals(target.name())) { - candidates.add(minsn); - } - } - - if (candidates.size() != 1) { - return Patch.Result.PASS; - } - - MethodInsnNode insn = candidates.getFirst(); - String qualifier = Type.getObjectType(insn.owner) + insn.name + insn.desc; - targetHandle.set(qualifier); - return Patch.Result.APPLY; - } - - private static boolean passesSliceCheck(AnnotationHandle slice, MethodContext methodContext) { - MethodContext.TargetPair dirtyTarget = methodContext.findDirtyInjectionTarget(); - Target mixinTarget = MockMixinRuntime.createMixinTarget(dirtyTarget); - - IMixinContext mixinContext = MockMixinRuntime.forClass(methodContext.getMixinClass().name, dirtyTarget.classNode().name, methodContext.patchContext().environment()); - ISliceContext sliceContext = MockMixinRuntime.forSlice(mixinContext, methodContext.getMixinMethod()); - MethodSlice methodSlice = MethodSlice.parse(sliceContext, slice.unwrap()); - InsnList insns = methodSlice.getSlice(mixinTarget); - - return insns.size() != dirtyTarget.methodNode().instructions.size(); - } -} 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 699cba99..275504f1 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 @@ -17,7 +17,6 @@ public class DynamicInjectionPointPatch implements MethodTransform { new DynFixLocalCaptureUpgrade() ); private static final List> FIXES = List.of( - new DynFixSliceBoundary(), new DynFixAtVariableAssignStore(), new DynFixParameterTypeAdapter(), new DynFixMethodComparison() diff --git a/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java index 5049dda9..7da3f188 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java @@ -22,7 +22,9 @@ public class PipelineLegacyMethodTransformer implements MethodTransform { @Override public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - if (methodContext.findCleanInjectionTarget() == null || !methodContext.failsDirtyInjectionCheck()) { + if (methodContext.findCleanInjectionTarget() == null + || !methodContext.failsDirtyInjectionCheck() && methodContext.hasValidSlice(methodContext.findDirtyInjectionTarget()) + ) { return Patch.Result.PASS; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java index b42b831f..f41c5873 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java @@ -2,16 +2,20 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.patch.api.MixinConstants; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.Objects; import java.util.Optional; import java.util.OptionalInt; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.*; + public class AtData { @NotNull private final String value; @@ -58,6 +62,20 @@ public void apply(AnnotationHandle handle) { } } + public AnnotationNode toAnnotationNode() { + AnnotationNode node = new AnnotationNode(MixinConstants.AT); + node.visit(AT_VALUE, Objects.requireNonNull(this.value)); + node.visit(AT_TARGET, Objects.requireNonNull(this.target)); + if (this.ordinal != null) { + node.visit(PROPERTY_ORDINAL, this.ordinal); + } + return node; + } + + public AtData withTarget(MethodInsnNode insn) { + return withTarget(MethodQualifier.create(insn)); + } + public AtData withTarget(MethodQualifier target) { return withTarget(target.asDescriptor()); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java index 83505a6a..15c39432 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java @@ -2,6 +2,8 @@ public class MixinAnnotationConstants { public static final String AT_METHOD = "method"; + public static final String AT_TARGET = "target"; + public static final String AT_VALUE = "value"; public static final String AT_VAL_INVOKE = "INVOKE"; public static final String AT_VAL_STORE = "STORE"; public static final String AT_VAL_SINYTRA_INSTANCEOF = "sinytra:INSTANCEOF"; @@ -9,4 +11,8 @@ public class MixinAnnotationConstants { public static final String PROPERTY_ORDINAL = "ordinal"; public static final String PROPERTY_INDEX = "index"; + public static final String PROPERTY_SLICE = "slice"; + + public static final String SLICE_FROM = "from"; + public static final String SLICE_TO = "to"; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java index f6b61cde..af1a0565 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java @@ -1,5 +1,6 @@ package org.sinytra.adapter.next.env.ann; +import org.jetbrains.annotations.Nullable; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.OptionalInt; @@ -7,12 +8,15 @@ public class ModifyVariableMixinData extends MixinData { private final boolean argsOnly; private final Integer ordinal; + @Nullable + private final SliceData slice; - public ModifyVariableMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, boolean argsOnly, Integer ordinal) { + public ModifyVariableMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, boolean argsOnly, Integer ordinal, @Nullable SliceData slice) { super(targetClass, targetMethod, atData); this.argsOnly = argsOnly; this.ordinal = ordinal; + this.slice = slice; } public boolean argsOnly() { @@ -22,4 +26,9 @@ public boolean argsOnly() { public OptionalInt ordinal() { return this.ordinal != null ? OptionalInt.of(this.ordinal) : OptionalInt.empty(); } + + @Nullable + public SliceData slice() { + return this.slice; + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java index 8279ca57..83619ba6 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java @@ -1,8 +1,16 @@ package org.sinytra.adapter.next.env.ann; import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.tree.AnnotationNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.api.MixinConstants; + +import javax.management.AttributeNotFoundException; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.SLICE_FROM; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.SLICE_TO; public class SliceData { @Nullable @@ -15,13 +23,36 @@ public SliceData(@Nullable AtData from, @Nullable AtData to) { this.to = to; } + @Nullable + public AtData from() { + return this.from; + } + + @Nullable + public AtData to() { + return this.to; + } + public static SliceData parse(AnnotationHandle handle, MixinContext context) { - AtData from = handle.getNested("from") + AtData from = handle.getNested(SLICE_FROM) .flatMap(s -> AtData.parse(s, context)) .orElse(null); - AtData to = handle.getNested("to") + AtData to = handle.getNested(SLICE_TO) .flatMap(s -> AtData.parse(s, context)) .orElse(null); return new SliceData(from, to); } + + public AnnotationNode toAnnotationNode() { + AnnotationNode slice = new AnnotationNode(MixinConstants.SLICE); + if (this.from != null) { + AnnotationVisitor fromNode = slice.visitAnnotation(SLICE_FROM, MixinConstants.AT); + this.from.toAnnotationNode().accept(fromNode); + } + if (this.to != null) { + AnnotationVisitor fromNode = slice.visitAnnotation(SLICE_TO, MixinConstants.AT); + this.to.toAnnotationNode().accept(fromNode); + } + return slice; + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java index 0813d4bb..d63cd717 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java @@ -31,6 +31,7 @@ import java.util.function.Supplier; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_SHIFT; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; public class MethodHelper { @@ -174,7 +175,7 @@ private List computeInjectionTargetInsns(@Nullable MethodConte } private InsnList getSlicedInsns(AnnotationHandle parentAnnotation, ClassNode classNode, MethodNode injectorMethod, ClassNode targetClass, MethodNode targetMethod, PatchContext context, Target mixinTarget) { - return parentAnnotation.getValue("slice") + return parentAnnotation.getValue(PROPERTY_SLICE) .map(handle -> { Object value = handle.get(); return value instanceof List list ? (AnnotationNode) list.getFirst() : (AnnotationNode) value; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java index b6f339cd..3929848f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java @@ -30,6 +30,8 @@ public interface Configuration { Map getProperties(); + void inheritProperyIfAbsent(String key); + MutableConfiguration subConfig(); MutableConfiguration copy(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java index f712412e..09c06870 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java @@ -208,10 +208,20 @@ public Map getProperties() { } @Override - public MutableConfiguration setProperty(String key, T value) { + public MutableConfiguration setProperty(String key, @Nullable T value) { this.properties.put(key, value); return this; } + + @Override + public void inheritProperyIfAbsent(String key) { + if (this.parent == null) { + throw new IllegalStateException("Missing parent, cannot inherit property " + key); + } + if (!hasProperty(key)) { + this.parent.getProperty(key).ifPresent(o -> setProperty(key, o)); + } + } @Override public MutableConfiguration subConfig() { @@ -249,9 +259,8 @@ public void mergeFrom(Configuration other) { this.parameters.set(other.getParameters()); if (other.getReturnType() != null) this.returnType.set(other.getReturnType()); - if (other.shouldDelete()) { + if (other.shouldDelete()) this.delete.set(other.shouldDelete()); - } this.properties.putAll(other.getProperties()); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java index daaba537..c46229dc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java @@ -1,5 +1,6 @@ package org.sinytra.adapter.next.pipeline.config; +import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; @@ -35,7 +36,7 @@ static MutableConfiguration create() { MutableConfiguration inheritShouldDelete(); MutableConfiguration setShouldDelete(boolean delete); - MutableConfiguration setProperty(String key, T value); + MutableConfiguration setProperty(String key, @Nullable T value); void mergeFrom(Configuration other); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinMethodParametersProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinMethodParametersProcessor.java rename to definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java index a41643d7..b1f918a8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinMethodParametersProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java @@ -13,7 +13,7 @@ import java.util.List; -public class MixinMethodParametersProcessor implements Processor { +public class ParametersProcessor implements Processor { @Override public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { if (dirty.getParameters() == null) return TxResult.FAIL; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java index e40f9ca2..e9bd1caf 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java @@ -13,7 +13,7 @@ private void registerDefaultProcessors() { add(new MixinTypeProcessor()); add(new TargetMethodProcessor()); add(new InjectionTargetProcessor()); - add(new MixinMethodParametersProcessor()); + add(new ParametersProcessor()); add(new ReturnTypeProcessor()); add(new PropertyProcessor()); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java index 6fd953d3..bc3e3847 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java @@ -2,12 +2,14 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.env.ann.SliceData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_ORDINAL; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; public class PropertyProcessor implements Processor { @Override @@ -18,6 +20,9 @@ public TxResult process(MixinData mixin, MixinContext context, Configuration dir dirty.getProperty(PROPERTY_ORDINAL) .ifPresent(o -> handle.setOrAppendNonNull(PROPERTY_ORDINAL, o)); + dirty.getProperty(PROPERTY_SLICE) + .ifPresent(s -> handle.setOrAppendNonNull(PROPERTY_SLICE, s.toAnnotationNode())); + return TxResult.SUCCESS; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java index fc444eb9..eadbfd9e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java @@ -2,6 +2,7 @@ import org.sinytra.adapter.next.env.OrderedRegistry; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.next.pipeline.resolver.special.SliceBoundaryResolver; import org.sinytra.adapter.next.pipeline.resolver.target.TargetMethodResolver; public class Resolvers extends OrderedRegistry { @@ -12,6 +13,7 @@ public Resolvers() { private void registerDefaultResolvers() { add(new TargetMethodResolver()); + add(new SliceBoundaryResolver()); add(new InjectionPointResolver()); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java new file mode 100644 index 00000000..8d68d8f8 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java @@ -0,0 +1,98 @@ +package org.sinytra.adapter.next.pipeline.resolver.special; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.env.ann.SliceData; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.resolver.Resolver; +import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.patch.util.MockMixinRuntime; +import org.spongepowered.asm.mixin.injection.code.ISliceContext; +import org.spongepowered.asm.mixin.injection.code.MethodSlice; +import org.spongepowered.asm.mixin.injection.struct.Target; +import org.spongepowered.asm.mixin.refmap.IMixinContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; + +public class SliceBoundaryResolver implements Resolver { + @Override + public ResolutionResult resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { + MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + + SliceData slice = clean.getProperty(PROPERTY_SLICE).orElse(null); + if (slice == null || passesSliceCheck(slice, context, dirtyTarget)) + return ResolutionResult.pass(); + + SliceData fixedSlice = fixSliceData(slice, dirtyTarget.methodNode()); + if (fixedSlice == null) + return ResolutionResult.pass(); + + Configuration patch = MutableConfiguration.create() + .setProperty(PROPERTY_SLICE, fixedSlice); + + return ResolutionResult.success(patch); + } + + @Nullable + private static SliceData fixSliceData(SliceData slice, MethodNode dirtyMethod) { + AtData from = slice.from(); + if (from != null) { + from = fixSlideInjectionPoint(from, dirtyMethod).orElse(null); + if (from == null) return null; + } + + AtData to = slice.to(); + if (to != null) { + to = fixSlideInjectionPoint(to, dirtyMethod).orElse(null); + if (to == null) return null; + } + + return new SliceData(from, to); + } + + private static Optional fixSlideInjectionPoint(AtData boundary, MethodNode dirtyMethod) { + // Require only INVOKE values + if (!AT_VAL_INVOKE.equals(boundary.getValue())) + return Optional.empty(); + + // Find original target invocation qualifier + MethodQualifier target = boundary.getTarget().flatMap(MethodQualifier::create).orElse(null); + if (target == null) return Optional.empty(); + + // Find method invocations with a matching name + List candidates = new ArrayList<>(); + for (AbstractInsnNode insn : dirtyMethod.instructions) { + if (insn instanceof MethodInsnNode minsn && minsn.name.equals(target.name())) { + candidates.add(minsn); + } + } + if (candidates.size() != 1) return Optional.empty(); + + MethodInsnNode insn = candidates.getFirst(); + return Optional.of(boundary.withTarget(insn)); + } + + private static boolean passesSliceCheck(SliceData slice, MixinContext context, MethodContext.TargetPair dirtyTarget) { + Target mixinTarget = MockMixinRuntime.createMixinTarget(dirtyTarget); + IMixinContext mixinContext = MockMixinRuntime.forClass(context.classNode().name, dirtyTarget.classNode().name, context.patchContext().environment()); + ISliceContext sliceContext = MockMixinRuntime.forSlice(mixinContext, context.methodNode()); + MethodSlice methodSlice = MethodSlice.parse(sliceContext, slice.toAnnotationNode()); + InsnList insns = methodSlice.getSlice(mixinTarget); + + return insns.size() != dirtyTarget.methodNode().instructions.size(); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java index 0f63ef59..b548008a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java @@ -17,12 +17,13 @@ import java.util.List; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; public class InjectMixin implements MixinType { @Override public InjectMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { - List slice = handle.getNestedList("slice").stream() + List slice = handle.getNestedList(PROPERTY_SLICE).stream() .map(s -> SliceData.parse(s, context)) .toList(); return new InjectMixinData(targetClass, targetMethod, atData, slice); @@ -35,7 +36,7 @@ public void preProcess(InjectMixinData mixin, MixinContext context, MutableConfi clean.setParameters(MethodParameters.create(context.methodNode(), List.of(METHOD_PARAMS, CI_CIR, LOCALS))); if (!mixin.getSlice().isEmpty()) { - clean.setProperty("slice", mixin.getSlice()); +// clean.setProperty("slice", mixin.getSlice()); TODO Handle multile and single slices using one interface } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java index 7fc99568..2ff670a5 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java @@ -5,6 +5,7 @@ import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.next.env.ann.ModifyVariableMixinData; +import org.sinytra.adapter.next.env.ann.SliceData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; @@ -18,6 +19,8 @@ import java.util.List; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_ORDINAL; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.LOCALS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; @@ -26,19 +29,25 @@ public class ModifyVariableMixin implements MixinType { @Override public ModifyVariableMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { boolean argsOnly = handle.getValue("argsOnly").map(AnnotationValueHandle::get).orElse(false); - Integer ordinal = handle.getValue("ordinal").map(AnnotationValueHandle::get).orElse(null); - return new ModifyVariableMixinData(targetClass, targetMethod, atData, argsOnly, ordinal); + Integer ordinal = handle.getValue(PROPERTY_ORDINAL).map(AnnotationValueHandle::get).orElse(null); + SliceData slice = handle.getNested(PROPERTY_SLICE) + .map(s -> SliceData.parse(s, context)) + .orElse(null); + return new ModifyVariableMixinData(targetClass, targetMethod, atData, argsOnly, ordinal, slice); } @Override public void preProcess(ModifyVariableMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, LOCALS))); + clean.setProperty(PROPERTY_SLICE, mixin.slice()); recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ModifyVarInjectionPointSubResolver()); } @Override public void postProcess(ModifyVariableMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + dirty.inheritProperyIfAbsent(PROPERTY_SLICE); + if (mixin.argsOnly() && dirty.getTargetMethod() != null && !dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { Type cleanVarType = clean.getParameters().get(SINGLE_ANY).getFirst(); List cleanTargetMethodParams = MethodParameters.getParameterTypes(clean.getTargetMethod().desc()); diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java index 966a1719..97d8df9e 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java @@ -16,7 +16,7 @@ public class LivingEntityMixin { method = "travel", at = @At( value = "INVOKE_ASSIGN", - target = "Lnet/minecraft/world/entity/Entity;onGround()Z" + target = "Lnet/minecraft/world/entity/LivingEntity;onGround()Z" ), slice = @Slice( from = @At( @@ -33,7 +33,7 @@ private float getSlipperinessForIceSkates(float slipperiness) { method = "travel", at = @At( value = "INVOKE_ASSIGN", - target = "Lnet/minecraft/world/entity/Entity;onGround()Z" + target = "Lnet/minecraft/world/entity/LivingEntity;onGround()Z" ), slice = @Slice( from = @At( From e9c323ede594f64369f84c2394c36cbec6bbce1b Mon Sep 17 00:00:00 2001 From: Su5eD Date: Fri, 26 Dec 2025 22:14:28 +0100 Subject: [PATCH 02/27] Migrate DynFixAtVariableAssignStore to pipeline --- .../analysis/params/EnhancedParamsDiff.java | 6 +- .../dynfix/DynFixAtVariableAssignStore.java | 117 ------------------ .../dynfix/DynamicInjectionPointPatch.java | 1 - .../next/env/param/ParamDiffResolver.java | 4 +- .../pipeline/resolver/CompoundResolver.java | 3 +- .../AtVariableAssignStoreSubResolver.java | 95 ++++++++++++++ .../adapter/next/type/InjectMixin.java | 5 +- .../adapter/next/type/WrapOperationMixin.java | 5 + 8 files changed, 112 insertions(+), 124 deletions(-) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixAtVariableAssignStore.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java index 7a659edb..f164d523 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java @@ -289,7 +289,11 @@ private static SwapResult checkForSwaps(ParamsDiffSnapshotBuilder builder, List< Integer count = entry.getValue(); if (count == 1) { TypeWithContext inserted = clean.stream().filter(t -> t.type().equals(type)).findFirst().orElseThrow(); - tempDiff.remove(inserted.pos()); + int offset = rearrangeClean.indexOf(inserted); + if (offset == -1) { + throw new IllegalStateException("Missing inserted from clean list, bug?"); + } + tempDiff.remove(offset); cleanGroup.remove(type); rearrangeClean.remove(inserted); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixAtVariableAssignStore.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixAtVariableAssignStore.java deleted file mode 100644 index 79d4d0c3..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixAtVariableAssignStore.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynfix; - -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchAuditTrail; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionPoint; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionTarget; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.OpcodeUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * Find our new injection point with relation to variable assignments - */ -public class DynFixAtVariableAssignStore implements DynamicFixer { - private static final Set ACCEPTED_ANNOTATIONS = Set.of(MixinConstants.INJECT, MixinConstants.WRAP_OPERATION); - - public record Data(MethodNode cleanTargetMethod, MethodContext.TargetPair dirtyTarget, AbstractInsnNode cleanInjectionInsn) {} - - @Nullable - @Override - public Data prepare(MethodContext methodContext) { - if (methodContext.methodAnnotation().matchesAny(ACCEPTED_ANNOTATIONS) && methodContext.hasInjectionPointValue("INVOKE")) { - MethodContext.TargetPair cleanInjectionTarget = methodContext.findCleanInjectionTarget(); - List cleanInsns = methodContext.findInjectionTargetInsns(cleanInjectionTarget); - if (cleanInsns.size() != 1) { - return null; - } - MethodContext.TargetPair dirtyInjectionTarget = methodContext.findDirtyInjectionTarget(); - if (dirtyInjectionTarget == null) { - return null; - } - return new Data(cleanInjectionTarget.methodNode(), dirtyInjectionTarget, cleanInsns.getFirst()); - } - return null; - } - - @Override - @Nullable - public FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchAuditTrail auditTrail, Data data) { - MethodNode cleanTargetMethod = data.cleanTargetMethod(); - MethodNode dirtyTargetMethod = data.dirtyTarget().methodNode(); - AbstractInsnNode cleanInjectionInsn = data.cleanInjectionInsn(); - - // Check that the following instruction is a store operation - AbstractInsnNode next = findNextUsefulInsn(cleanInjectionInsn); - if (!(next instanceof VarInsnNode varInsn) || !OpcodeUtil.isStoreOpcode(varInsn.getOpcode())) { - return null; - } - // Find matching local in dirty target method - LocalVariableNode cleanLocal = methodContext.cleanLocalsTable().getByIndexOrNull(varInsn.var); - if (cleanLocal == null) { - return null; - } - List cleanLocals = methodContext.cleanLocalsTable().getForType(cleanLocal); - List dirtyLocals = methodContext.dirtyLocalsTable().getForType(cleanLocal); - if (cleanLocals.size() != dirtyLocals.size()) { - return null; - } - LocalVariableNode dirtyLocal = dirtyLocals.get(cleanLocals.indexOf(cleanLocal)); - // Find store insns - List cleanStoreInsns = findStoreInsns(cleanTargetMethod.instructions, cleanLocal.index); - int cleanStoreInsnIndex = cleanStoreInsns.indexOf(varInsn); - if (cleanStoreInsnIndex == -1) { - return null; - } - List dirtyStoreInsns = findStoreInsns(dirtyTargetMethod.instructions, dirtyLocal.index); - if (cleanStoreInsns.size() != dirtyStoreInsns.size()) { - return null; - } - AbstractInsnNode dirtyStoreInsn = dirtyStoreInsns.get(cleanStoreInsnIndex); - // Find first method call before dirty store - MethodInsnNode previousMethodCall = (MethodInsnNode) AdapterUtil.iterateInsns(dirtyStoreInsn, AbstractInsnNode::getPrevious, i -> i instanceof MethodInsnNode); - if (previousMethodCall == null) { - return null; - } - - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { - return handleWrapAnnotation(methodContext, data, previousMethodCall); - } - - // All checks have passed, proceed to patch method - String newInjectionPoint = Type.getObjectType(previousMethodCall.owner).getDescriptor() + previousMethodCall.name + previousMethodCall.desc; - return FixResult.of(new ModifyInjectionPoint((String) null, newInjectionPoint, true, true) - .apply(methodContext), PatchAuditTrail.Match.FULL); - } - - // In case the mixin is call-sensitive, we try to keep the orignal injection point if the method was moved - @Nullable - private static FixResult handleWrapAnnotation(MethodContext methodContext, Data data, MethodInsnNode previousMethodCall) { - if (previousMethodCall.owner.equals(data.dirtyTarget().classNode().name)) { - String newTarget = previousMethodCall.name + previousMethodCall.desc; - return FixResult.of(new ModifyInjectionTarget(List.of(newTarget)).apply(methodContext), PatchAuditTrail.Match.FULL); - } - return null; - } - - private static List findStoreInsns(InsnList insns, int index) { - List list = new ArrayList<>(); - for (AbstractInsnNode insn : insns) { - if (insn instanceof VarInsnNode varInsn && varInsn.var == index && OpcodeUtil.isStoreOpcode(varInsn.getOpcode())) { - list.add(insn); - } - } - return list; - } - - private static AbstractInsnNode findNextUsefulInsn(AbstractInsnNode insn) { - return AdapterUtil.iterateInsns(insn, AbstractInsnNode::getNext, i -> !(i instanceof TypeInsnNode || i instanceof FrameNode || i instanceof LineNumberNode || i instanceof LabelNode)); - } -} 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 275504f1..40169033 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 @@ -17,7 +17,6 @@ public class DynamicInjectionPointPatch implements MethodTransform { new DynFixLocalCaptureUpgrade() ); private static final List> FIXES = List.of( - new DynFixAtVariableAssignStore(), new DynFixParameterTypeAdapter(), new DynFixMethodComparison() ); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/ParamDiffResolver.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/ParamDiffResolver.java index 359d9644..3ec36c96 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/ParamDiffResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/ParamDiffResolver.java @@ -62,9 +62,7 @@ case SwapParam(int from, int to) -> { state.set(from, dirty); state.set(to, clean); } - case MoveParam(int from, int to) -> { - state.add(to, state.remove(from)); - } + case MoveParam(int from, int to) -> state.add(to, state.remove(from)); case RemoveParam(int index) -> state.remove(index); case InlineParam inline -> state.remove(inline.target()); case SubstituteParam substitute -> state.remove(substitute.target()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java index d23a6206..da43790a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java @@ -12,8 +12,9 @@ public abstract class CompoundResolver implements Resolver { protected final List subResolvers = new ArrayList<>(); - public void addSubResolver(SubResolver subResolver) { + public CompoundResolver addSubResolver(SubResolver subResolver) { this.subResolvers.add(subResolver); + return this; } protected abstract boolean canApply(MixinData mixin, Configuration clean, Configuration dirty); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java new file mode 100644 index 00000000..5d5e6cb2 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java @@ -0,0 +1,95 @@ +package org.sinytra.adapter.next.pipeline.resolver.injection; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.resolver.SubResolver; +import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.OpcodeUtil; + +import java.util.ArrayList; +import java.util.List; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; + +/** + * Find our new injection point with relation to variable assignments + */ +public class AtVariableAssignStoreSubResolver implements SubResolver { + @Nullable + @Override + public Configuration resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { + if (!clean.getAtData().getValue().equals(AT_VAL_INVOKE)) return null; + + MethodContext.TargetPair cleanPair = context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); + AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanPair); + if (cleanInsn == null) return null; + + MethodContext.TargetPair dirtyPair = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + if (dirtyPair == null) return null; + + // Check that the following instruction is a store operation + AbstractInsnNode next = findNextUsefulInsn(cleanInsn); + if (!(next instanceof VarInsnNode varInsn) || !OpcodeUtil.isStoreOpcode(varInsn.getOpcode())) { + return null; + } + // Find matching local in dirty target method + LocalVariableNode cleanLocal = context.legacy().cleanLocalsTable().getByIndexOrNull(varInsn.var); + if (cleanLocal == null) { + return null; + } + List cleanLocals = context.legacy().cleanLocalsTable().getForType(cleanLocal); + List dirtyLocals = context.legacy().dirtyLocalsTable().getForType(cleanLocal); + if (cleanLocals.size() != dirtyLocals.size()) { + return null; + } + LocalVariableNode dirtyLocal = dirtyLocals.get(cleanLocals.indexOf(cleanLocal)); + // Find store insns + List cleanStoreInsns = findStoreInsns(cleanPair.methodNode().instructions, cleanLocal.index); + int cleanStoreInsnIndex = cleanStoreInsns.indexOf(varInsn); + if (cleanStoreInsnIndex == -1) { + return null; + } + List dirtyStoreInsns = findStoreInsns(dirtyPair.methodNode().instructions, dirtyLocal.index); + if (cleanStoreInsns.size() != dirtyStoreInsns.size()) { + return null; + } + AbstractInsnNode dirtyStoreInsn = dirtyStoreInsns.get(cleanStoreInsnIndex); + // Find first method call before dirty store + MethodInsnNode previousMethodCall = (MethodInsnNode) AdapterUtil.iterateInsns(dirtyStoreInsn, AbstractInsnNode::getPrevious, i -> i instanceof MethodInsnNode); + if (previousMethodCall == null) { + return null; + } + + if (context.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { + // In case the mixin is call-sensitive, we try to keep the orignal injection point if the method was moved + if (!previousMethodCall.owner.equals(dirtyPair.classNode().name)) { + return null; + } + } + + // All checks have passed, proceed to patch method + return MutableConfiguration.create() + .setAtData(clean.getAtData().withTarget(previousMethodCall)); + } + + private static List findStoreInsns(InsnList insns, int index) { + List list = new ArrayList<>(); + for (AbstractInsnNode insn : insns) { + if (insn instanceof VarInsnNode varInsn && varInsn.var == index && OpcodeUtil.isStoreOpcode(varInsn.getOpcode())) { + list.add(insn); + } + } + return list; + } + + private static AbstractInsnNode findNextUsefulInsn(AbstractInsnNode insn) { + return AdapterUtil.iterateInsns(insn, AbstractInsnNode::getNext, i -> !(i instanceof TypeInsnNode || i instanceof FrameNode || i instanceof LineNumberNode || i instanceof LabelNode)); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java index b548008a..c64d51e3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java @@ -11,6 +11,7 @@ import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; +import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -31,7 +32,9 @@ public InjectMixinData parse(MixinContext context, ClassTarget targetClass, Meth @Override public void preProcess(InjectMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ArbitraryInjectionPointSubResolver()); + recipe.resolvers().getOrThrow(InjectionPointResolver.class) + .addSubResolver(new AtVariableAssignStoreSubResolver()) + .addSubResolver(new ArbitraryInjectionPointSubResolver()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(METHOD_PARAMS, CI_CIR, LOCALS))); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java index f17e8481..29c8b271 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java @@ -11,6 +11,8 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; +import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -28,6 +30,9 @@ public WrapOperationMixinData parse(MixinContext context, ClassTarget targetClas @Override public void preProcess(WrapOperationMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + recipe.resolvers().getOrThrow(InjectionPointResolver.class) + .addSubResolver(new AtVariableAssignStoreSubResolver()); + clean.setParameters(MethodParameters.create(context.methodNode(), List.of(METHOD_PARAMS, OPERATION, CAPTURED_PARAMS, LOCALS))); } From 83cbec92794607d222ce730404a01a05eba7d232 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sat, 27 Dec 2025 17:51:51 +0100 Subject: [PATCH 03/27] Migrate DynFixParameterTypeAdapter to pipeline --- .../dynfix/DynFixParameterTypeAdapter.java | 103 ------------------ .../dynfix/DynamicInjectionPointPatch.java | 1 - .../next/env/param/MethodParameters.java | 4 + .../next/pipeline/PipelineExecutor.java | 2 + .../processor/ParameterUsageProcessor.java | 39 +++++++ .../adapter/next/type/RedirectMixin.java | 3 + .../test/mixin/CrossbowAttackGoalMixin.java | 27 ++--- 7 files changed, 62 insertions(+), 117 deletions(-) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixParameterTypeAdapter.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java 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 deleted file mode 100644 index 171d76fe..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixParameterTypeAdapter.java +++ /dev/null @@ -1,103 +0,0 @@ -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.*; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; -import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; -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.transformer.operation.CompoundMethodTransform; -import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformTarget; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -public class DynFixParameterTypeAdapter implements DynamicFixer { - public record Data(MethodInsnNode newCall, ParamsDiffSnapshot diff, Set> modifyCalls, MethodQualifier qualifier) {} - - @Nullable - @Override - public Data prepare(MethodContext methodContext) { - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.REDIRECT)) { - MethodQualifier qualifier = methodContext.getInjectionPointMethodQualifier(); - if (qualifier == null) { - return null; - } - MethodContext.TargetPair dirtyPair = methodContext.findDirtyInjectionTarget(); - if (dirtyPair == null) { - return null; - } - List newMethodCalls = StreamSupport.stream(dirtyPair.methodNode().instructions.spliterator(), false) - .filter(i -> i instanceof MethodInsnNode minsn && minsn.owner.equals(qualifier.internalOwnerName()) && minsn.name.equals(qualifier.name()) && !minsn.desc.equals(qualifier.desc())) - .map(i -> (MethodInsnNode) i) - .toList(); - if (newMethodCalls.size() != 1) { - return null; - } - MethodInsnNode newCall = newMethodCalls.getFirst(); - LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(List.of(Type.getArgumentTypes(qualifier.desc())), List.of(Type.getArgumentTypes(newCall.desc))); - Set> modifyCalls = validateReplacements(methodContext, qualifier, diff.replacements()); - if (modifyCalls == null) { - return null; - } - return new Data(newCall, diff, modifyCalls, qualifier); - } - return null; - } - - @Override - @Nullable - public FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchAuditTrail auditTrail, Data data) { - Patch.Result result = CompoundMethodTransform.builder(b -> b - .modifyInjectionPoint(MethodCallAnalyzer.getCallQualifier(data.newCall())) - .transform(data.diff().asParameterTransformer(ParamTransformTarget.INJECTION_POINT, false))) - .apply(methodContext); - if (result == Patch.Result.PASS) { - return null; - } - - MethodQualifier qualifier = data.qualifier(); - for (List call : data.modifyCalls()) { - for (AbstractInsnNode insn : call) { - if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { - minsn.desc = data.newCall().desc; - } - } - } - - return FixResult.of(result.or(Patch.Result.APPLY), PatchAuditTrail.Match.FULL); - } - - @Nullable - private static Set> validateReplacements(MethodContext methodContext, MethodQualifier qualifier, List> replacements) { - MethodNode mixinMethod = methodContext.getMixinMethod(); - List> insns = MethodCallAnalyzer.getInvocationInsns(mixinMethod, qualifier); - - LocalVariableLookup lookup = new LocalVariableLookup(methodContext.getMixinMethod()); - Set paramVars = replacements.stream().map(p -> lookup.getByParameterOrdinal(p.getFirst()).index).collect(Collectors.toSet()); - - Set> usedInsns = new HashSet<>(); - for (AbstractInsnNode insn : methodContext.getMixinMethod().instructions) { - if (insn instanceof VarInsnNode varInsn && paramVars.contains(varInsn.var)) { - List call = insns.stream().filter(l -> l.contains(varInsn)).findFirst().orElse(null); - if (call == null) { - return null; - } - usedInsns.add(call); - } - } - - return usedInsns; - } -} 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 40169033..57bd225a 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 @@ -17,7 +17,6 @@ public class DynamicInjectionPointPatch implements MethodTransform { new DynFixLocalCaptureUpgrade() ); private static final List> FIXES = List.of( - new DynFixParameterTypeAdapter(), new DynFixMethodComparison() ); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java index b67e6a44..ebfd7719 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java @@ -36,6 +36,10 @@ private MethodParameters(Map> groups, List or this.order = order; } + public boolean has(ParamGroup group) { + return this.groups.containsKey(group); + } + public List get(ParamGroup group) { return Objects.requireNonNull(this.groups.get(group), "Group %s is not available".formatted(group.name())); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java index 5151a599..de81d625 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java @@ -89,6 +89,8 @@ public Patch.Result execute() { } } + // TODO Check and make sure resolvers don't modify the method/class (maybe with a propert switch to skip these in prod) + // 4. Complete dirty config this.mixinType.postProcess(data, this.context, cleanConfig, dirtyConfig, recipe); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java new file mode 100644 index 00000000..994cb378 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java @@ -0,0 +1,39 @@ +package org.sinytra.adapter.next.pipeline.processor; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.patch.util.MethodQualifier; + +public class ParameterUsageProcessor implements Processor { + @Override + public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { +// Configuration clean = recipe.clean(); + String cleanTarget = recipe.clean().getAtData().getTarget().orElse(null); + if (cleanTarget == null) return TxResult.PASS; + String dirtyTarget = dirty.getAtData().getTarget().orElse(null); + if (dirtyTarget == null) return TxResult.PASS; + +// if (cleanTarget.equals(dirtyTarget) || !clean.getParameters().has(ParamGroup.METHOD_PARAMS) +// || !dirty.getParameters().has(ParamGroup.METHOD_PARAMS) +// ) return TxResult.PASS; + + MethodQualifier cleanTargetQual = MethodQualifier.create(cleanTarget).orElseThrow(); + MethodQualifier dirtyTargetQual = MethodQualifier.create(dirtyTarget).orElseThrow(); + for (AbstractInsnNode insn : context.methodNode().instructions) { + if (insn instanceof MethodInsnNode minsn && cleanTargetQual.matches(minsn)) { + if (dirtyTargetQual.owner() != null) { + minsn.owner = dirtyTargetQual.internalOwnerName(); + } + minsn.name = dirtyTargetQual.name(); + minsn.desc = dirtyTargetQual.desc(); + } + } + + return TxResult.SUCCESS; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java index 5af8122d..4fb00ba9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java @@ -10,6 +10,8 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.processor.ParameterUsageProcessor; +import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; @@ -30,6 +32,7 @@ public RedirectMixinData parse(MixinContext context, ClassTarget targetClass, Me @Override public void preProcess(RedirectMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { recipe.resolvers().addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(false)); + recipe.processors().addAfter(ParametersProcessor.class, new ParameterUsageProcessor()); if (clean.getAtData() == null || !MixinAnnotationConstants.AT_VAL_INVOKE.equals(clean.getAtData().getValue())) return; diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java index 4169ce49..60c89781 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java @@ -2,16 +2,13 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.LivingEntity; -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 net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.item.Item; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -19,21 +16,25 @@ @Mixin(RangedCrossbowAttackGoal.class) public abstract class CrossbowAttackGoalMixin extends Goal { - @Shadow - @Final - private T mob; - - @Shadow - @Final - private Mob mobExpected; - // https://github.com/SolipIngen/minecraft.progressivearchery/blob/7af8bdb7ddc24d73163d17de082add89716755cb/src/main/java/solipingen/progressivearchery/mixin/entity/ai/goal/CrossbowAttackGoalMixin.java#L42 - @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getWeaponHoldingHand(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/Item;)Lnet/minecraft/world/InteractionHand;")) + @Redirect( + method = "tick()V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getWeaponHoldingHand(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/Item;)Lnet/minecraft/world/InteractionHand;" + ) + ) private InteractionHand redirectedGetHandPossiblyHolding(LivingEntity entity, Item item) { return ProjectileUtil.getWeaponHoldingHand(entity, item); } - @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getWeaponHoldingHand(Lnet/minecraft/world/entity/LivingEntity;Ljava/util/function/Predicate;)Lnet/minecraft/world/InteractionHand;")) + @Redirect( + method = "tick()V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getWeaponHoldingHand(Lnet/minecraft/world/entity/LivingEntity;Ljava/util/function/Predicate;)Lnet/minecraft/world/InteractionHand;" + ) + ) private InteractionHand redirectedGetHandPossiblyHoldingExpected(LivingEntity entity, Predicate item) { return ProjectileUtil.getWeaponHoldingHand(entity, item); } From 36f174caf8ab1667ce3e66244e083a6ccdb5be5d Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sat, 27 Dec 2025 21:42:46 +0100 Subject: [PATCH 04/27] Dynamic property containers --- .../next/env/ConfigurationTemplates.java | 16 ++ .../next/pipeline/PipelineExecutor.java | 6 +- .../config/BasePropertyContainer.java | 80 +++++++ .../next/pipeline/config/Configuration.java | 37 +-- .../pipeline/config/ConfigurationImpl.java | 210 ++++++------------ .../pipeline/config/MutableConfiguration.java | 19 +- .../config/MutablePropertyContainer.java | 9 + .../pipeline/config/PropertyContainer.java | 16 ++ .../config/PropertyContainerTemplate.java | 65 ++++++ .../next/pipeline/config/PropertyKey.java | 28 +++ .../pipeline/processor/PropertyProcessor.java | 14 +- .../ModifyVarInjectionPointSubResolver.java | 4 +- .../special/SliceBoundaryResolver.java | 5 +- .../adapter/next/type/InjectMixin.java | 7 + .../sinytra/adapter/next/type/MixinType.java | 3 + .../adapter/next/type/ModifyArgMixin.java | 19 +- .../next/type/ModifyExpressionValueMixin.java | 7 + .../next/type/ModifyVariableMixin.java | 11 +- .../adapter/next/type/RedirectMixin.java | 9 +- .../adapter/next/type/WrapOperationMixin.java | 7 + .../test/mixin/CrossbowAttackGoalMixin.java | 11 + 21 files changed, 402 insertions(+), 181 deletions(-) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainer.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java new file mode 100644 index 00000000..f887fcdc --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java @@ -0,0 +1,16 @@ +package org.sinytra.adapter.next.env; + +import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; + +public final class ConfigurationTemplates { + public static final PropertyContainerTemplate MIXIN_BASE = PropertyContainerTemplate.builder() + .require(Keys.MIXIN_TYPE, Keys.TARGET_CLASS, Keys.TARGET_METHOD, Keys.PARAMETERS, Keys.RETURN_TYPE) + .build(); + public static final PropertyContainerTemplate MIXIN_AT = MIXIN_BASE.extend() + .require(Keys.TARGET_AT) + .build(); + + private ConfigurationTemplates() { + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java index de81d625..ed9f9a56 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java @@ -8,6 +8,7 @@ import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.config.ConfigurationImpl; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.processor.Processor; import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.resolver.Resolver; @@ -47,9 +48,10 @@ public Patch.Result execute() { Resolvers resolvers = new Resolvers(); Processors processors = new Processors(); + PropertyContainerTemplate template = Objects.requireNonNull(this.mixinType.getConfigurationTemplate()); // 1. Create clean config - ConfigurationImpl cleanConfig = new ConfigurationImpl(); + ConfigurationImpl cleanConfig = new ConfigurationImpl(template); cleanConfig.setMixinType(this.context.methodAnnotation().getDesc()); cleanConfig.setTargetClass(data.getTargetClass()); cleanConfig.setTargetMethod(data.getTargetMethod()); @@ -57,7 +59,7 @@ public Patch.Result execute() { cleanConfig.setReturnType(Type.getReturnType(context.methodNode().desc)); // 1.1. Create dirty config - ConfigurationImpl dirtyConfig = new ConfigurationImpl(cleanConfig); + ConfigurationImpl dirtyConfig = new ConfigurationImpl(template, cleanConfig); dirtyConfig.inheritMixinType(); dirtyConfig.inheritTargetClass(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java new file mode 100644 index 00000000..d52e3311 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java @@ -0,0 +1,80 @@ +package org.sinytra.adapter.next.pipeline.config; + +import com.google.common.collect.ImmutableMap; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class BasePropertyContainer implements MutablePropertyContainer { + private final Map, Object> properties = new HashMap<>(); + @Nullable + protected final PropertyContainerTemplate template; + + public BasePropertyContainer() { + this(null); + } + + public BasePropertyContainer(@Nullable PropertyContainerTemplate template) { + this.template = template; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public boolean validate() { + if (this.template != null && !this.template.validate(this)) { + return false; + } + + for (Map.Entry, Object> entry : this.properties.entrySet()) { + PropertyKey key = entry.getKey(); + if (!key.validate(entry.getValue())) { + return false; + } + } + return true; + } + + @Override + public boolean hasProperty(PropertyKey key) { + return this.properties.containsKey(key); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getProperty(PropertyKey key) { + T value = (T) this.properties.get(key); + return Optional.ofNullable(value); + } + + @Override + public MutablePropertyContainer setProperty(PropertyKey key, @Nullable T value) { + this.properties.put(key, value); + return this; + } + + @Override + public Map, Object> getProperties() { + return ImmutableMap.copyOf(this.properties); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public MutablePropertyContainer copy() { + MutablePropertyContainer copy = createCopyImpl(); + this.properties.forEach((p, v) -> copy.setProperty((PropertyKey) p, v)); + return copy; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public MutablePropertyContainer mergeFrom(PropertyContainer other) { + other.getProperties().forEach((p, v) -> setProperty((PropertyKey) p, v)); + return this; + } + + protected MutablePropertyContainer createCopyImpl() { + return new BasePropertyContainer(); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java index 3929848f..1306fb15 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java @@ -2,13 +2,11 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.ann.SliceData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.patch.util.MethodQualifier; -import java.util.Map; -import java.util.Optional; - -public interface Configuration { +public interface Configuration extends PropertyContainer { String getMixinType(); String getTargetClass(); @@ -18,21 +16,32 @@ public interface Configuration { AtData getAtData(); MethodParameters getParameters(); - + Type getReturnType(); boolean shouldDelete(); - // TODO Common PropertyContainer for configs and AtData - boolean hasProperty(String key); - - Optional getProperty(String key); - - Map getProperties(); - - void inheritProperyIfAbsent(String key); - MutableConfiguration subConfig(); MutableConfiguration copy(); + + final class Keys { + // Mixin meta + public static final PropertyKey MIXIN_TYPE = new PropertyKey<>("mixin_type"); + public static final PropertyKey TARGET_CLASS = new PropertyKey<>("target_class"); + public static final PropertyKey TARGET_METHOD = new PropertyKey<>("target_method"); + public static final PropertyKey TARGET_AT = new PropertyKey<>("target_at"); + // Method + public static final PropertyKey PARAMETERS = new PropertyKey<>("parameters"); + public static final PropertyKey RETURN_TYPE = new PropertyKey<>("return_type"); + // Control + public static final PropertyKey DELETE = new PropertyKey<>("delete"); + // Misc + public static final PropertyKey ORDINAL = new PropertyKey<>("ordinal"); + public static final PropertyKey INDEX = new PropertyKey<>("index"); + public static final PropertyKey SLICE = new PropertyKey<>("slice"); + + private Keys() { + } + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java index 09c06870..dd28b4fd 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java @@ -1,6 +1,5 @@ package org.sinytra.adapter.next.pipeline.config; -import com.mojang.logging.LogUtils; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodInsnNode; @@ -8,146 +7,117 @@ import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.patch.util.MethodQualifier; -import org.slf4j.Logger; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; /** * Contains a single recipe state with mixin parameters and custom variables */ -public class ConfigurationImpl implements MutableConfiguration { - private static final Logger LOGGER = LogUtils.getLogger(); - +public class ConfigurationImpl extends BasePropertyContainer implements MutableConfiguration { @Nullable private final Configuration parent; - private final ConfigAttribute mixinType; - private final ConfigAttribute targetClass; - private final ConfigAttribute targetMethod; - private final ConfigAttribute atData; - private final ConfigAttribute parameters; - private final ConfigAttribute returnType; - private final ConfigAttribute delete; - - private final Map properties = new HashMap<>(); public ConfigurationImpl() { - this(null); + this(null, null); } - public ConfigurationImpl(@Nullable Configuration parent) { - this.parent = parent; + public ConfigurationImpl(@Nullable PropertyContainerTemplate template) { + this(template, null); + } - this.mixinType = new ConfigAttribute<>("mixin_type", true, parent != null ? parent::getMixinType : null); - this.targetClass = new ConfigAttribute<>("target_class", true, parent != null ? parent::getTargetClass : null); - this.targetMethod = new ConfigAttribute<>("target_method", true, parent != null ? parent::getTargetMethod : null); - this.atData = new ConfigAttribute<>("at_data", true, parent != null ? parent::getAtData : null); - this.parameters = new ConfigAttribute<>("parameters", true, parent != null ? parent::getParameters : null); - this.returnType = new ConfigAttribute<>("return_type", true, parent != null ? parent::getReturnType : null); - this.delete = new ConfigAttribute<>("delete", false, parent != null ? parent::shouldDelete : () -> false); - } - - public boolean validate() { - List> attrs = List.of(mixinType, targetClass, targetMethod, atData, parameters, returnType, delete); - for (ConfigAttribute attr : attrs) { - if (!attr.validate()) { - LOGGER.debug(MIXINPATCH, "Missing required config attribute: {}", attr.getKey()); - return false; - } - } - return true; + public ConfigurationImpl(@Nullable PropertyContainerTemplate template, @Nullable Configuration parent) { + super(template); + this.parent = parent; } @Override - public MutableConfiguration inheritMixinType() { - this.mixinType.setDefault(); - return this; + public MutableConfiguration setProperty(PropertyKey key, @Nullable T value) { + return (MutableConfiguration) super.setProperty(key, value); } @Override - public MutableConfiguration setMixinType(String mixinType) { - this.mixinType.set(mixinType); - return this; + public MutableConfiguration inheritMixinType() { + return inheritProperty(Keys.MIXIN_TYPE); } @Override public MutableConfiguration inheritTargetClass() { - this.targetClass.setDefault(); - return this; + return inheritProperty(Keys.TARGET_CLASS); } @Override public MutableConfiguration inheritTargetMethod() { - this.targetMethod.setDefault(); - return this; + return inheritProperty(Keys.TARGET_METHOD); } @Override public MutableConfiguration inheritAtData() { - this.atData.setDefault(); - return this; + return inheritProperty(Keys.TARGET_AT); } @Override public MutableConfiguration inheritParameters() { - this.parameters.setDefault(); - return this; + return inheritProperty(Keys.PARAMETERS); } @Override public MutableConfiguration inheritReturnType() { - this.returnType.setDefault(); - return this; + return inheritProperty(Keys.RETURN_TYPE); + } + + @Override + public MutableConfiguration inheritShouldDelete() { + return inheritProperty(Keys.DELETE); } @Override public String getMixinType() { - return this.mixinType.get(); + return getPropertyOrNull(Keys.MIXIN_TYPE); } @Override public String getTargetClass() { - return this.targetClass.get(); + return getPropertyOrNull(Keys.TARGET_CLASS); } @Override public MethodQualifier getTargetMethod() { - return this.targetMethod.get(); + return getPropertyOrNull(Keys.TARGET_METHOD); } @Override public AtData getAtData() { - return this.atData.get(); + return getPropertyOrNull(Keys.TARGET_AT); } @Override public MethodParameters getParameters() { - return this.parameters.get(); + return getPropertyOrNull(Keys.PARAMETERS); } @Override public Type getReturnType() { - return this.returnType.get(); + return getPropertyOrNull(Keys.RETURN_TYPE); + } + + @Override + public boolean shouldDelete() { + Boolean boxed = getProperty(Keys.DELETE).orElse(null); + return boxed != null && boxed.booleanValue(); } @Override public void setTargetClass(String targetClass) { - this.targetClass.set(targetClass); + setProperty(Keys.TARGET_CLASS, targetClass); } @Override - public MutableConfiguration setTargetMethod(MethodInsnNode insn) { - setTargetMethod(MethodQualifier.create(insn)); + public MutableConfiguration setMixinType(String mixinType) { + setProperty(Keys.MIXIN_TYPE, mixinType); return this; } @Override - public MutableConfiguration setTargetMethod(MethodQualifier targetMethod) { - this.targetMethod.set(targetMethod); + public MutableConfiguration setTargetMethod(MethodInsnNode insn) { + setTargetMethod(MethodQualifier.create(insn)); return this; } @@ -158,110 +128,70 @@ public MutableConfiguration setTargetMethod(MethodNode methodNode) { } @Override - public MutableConfiguration setAtData(AtData atData) { - this.atData.set(atData); + public MutableConfiguration setTargetMethod(MethodQualifier targetMethod) { + setProperty(Keys.TARGET_METHOD, targetMethod); return this; } @Override - public void setParameters(MethodParameters parameters) { - this.parameters.set(parameters); - } - - @Override - public void setReturnType(Type returnType) { - this.returnType.set(returnType); + public MutableConfiguration setAtData(AtData atData) { + setProperty(Keys.TARGET_AT, atData); + return this; } @Override - public boolean shouldDelete() { - Boolean boxed = this.delete.get(); - return boxed != null && boxed.booleanValue(); + public MutableConfiguration setParameters(MethodParameters parameters) { + setProperty(Keys.PARAMETERS, parameters); + return this; } @Override - public MutableConfiguration inheritShouldDelete() { - this.delete.setDefault(); + public MutableConfiguration setReturnType(Type returnType) { + setProperty(Keys.RETURN_TYPE, returnType); return this; } @Override public MutableConfiguration setShouldDelete(boolean delete) { - this.delete.set(delete); + setProperty(Keys.DELETE, delete); return this; } @Override - public boolean hasProperty(String key) { - return this.properties.containsKey(key); - } - - @SuppressWarnings("unchecked") - @Override - public Optional getProperty(String key) { - return Optional.ofNullable((T) this.properties.get(key)); - } - - @Override - public Map getProperties() { - return this.properties; - } - - @Override - public MutableConfiguration setProperty(String key, @Nullable T value) { - this.properties.put(key, value); - return this; - } - - @Override - public void inheritProperyIfAbsent(String key) { + public void inheritProperyIfAbsent(PropertyKey key) { if (this.parent == null) { throw new IllegalStateException("Missing parent, cannot inherit property " + key); } if (!hasProperty(key)) { - this.parent.getProperty(key).ifPresent(o -> setProperty(key, o)); + inheritProperty(key); } } + @SuppressWarnings({"unchecked", "rawtypes"}) + private ConfigurationImpl inheritProperty(PropertyKey key) { + if (this.parent != null) { + this.parent.getProperty(key).ifPresent(o -> setProperty((PropertyKey) key, o)); + } + return this; + } + + @Nullable + private T getPropertyOrNull(PropertyKey key) { + return getProperty(key).orElse(null); + } + @Override public MutableConfiguration subConfig() { - return new ConfigurationImpl(this.parent); + return new ConfigurationImpl(this.template, this.parent); } - // TODO Remove hardcoding in copy and merge @Override - public MutableConfiguration copy() { - MutableConfiguration copy = new ConfigurationImpl(this.parent); - - copy.setMixinType(this.mixinType.get()); - copy.setTargetClass(this.targetClass.get()); - copy.setTargetMethod(this.targetMethod.get()); - copy.setAtData(this.atData.get()); - copy.setParameters(this.parameters.get()); - copy.setReturnType(this.returnType.get()); - copy.setShouldDelete(shouldDelete()); - // TODO Properties - - return copy; + protected MutablePropertyContainer createCopyImpl() { + return subConfig(); } @Override - public void mergeFrom(Configuration other) { - if (other.getMixinType() != null) - this.mixinType.set(other.getMixinType()); - if (other.getTargetClass() != null) - this.targetClass.set(other.getTargetClass()); - if (other.getTargetMethod() != null) - this.targetMethod.set(other.getTargetMethod()); - if (other.getAtData() != null) - this.atData.set(other.getAtData()); - if (other.getParameters() != null) - this.parameters.set(other.getParameters()); - if (other.getReturnType() != null) - this.returnType.set(other.getReturnType()); - if (other.shouldDelete()) - this.delete.set(other.shouldDelete()); - - this.properties.putAll(other.getProperties()); + public MutableConfiguration copy() { + return (MutableConfiguration) super.copy(); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java index c46229dc..fdc436b5 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java @@ -8,35 +8,44 @@ import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.patch.util.MethodQualifier; -public interface MutableConfiguration extends Configuration { +public interface MutableConfiguration extends Configuration, MutablePropertyContainer { static MutableConfiguration create() { return new ConfigurationImpl(); } MutableConfiguration inheritMixinType(); + MutableConfiguration setMixinType(String mixinType); MutableConfiguration inheritTargetClass(); + void setTargetClass(String targetClass); MutableConfiguration inheritTargetMethod(); + MutableConfiguration setTargetMethod(MethodInsnNode insn); + MutableConfiguration setTargetMethod(MethodQualifier targetMethod); + MutableConfiguration setTargetMethod(MethodNode methodNode); MutableConfiguration inheritAtData(); + MutableConfiguration setAtData(AtData atData); MutableConfiguration inheritParameters(); - void setParameters(MethodParameters parameters); + + MutableConfiguration setParameters(MethodParameters parameters); MutableConfiguration inheritReturnType(); - void setReturnType(Type returnType); + + MutableConfiguration setReturnType(Type returnType); MutableConfiguration inheritShouldDelete(); + MutableConfiguration setShouldDelete(boolean delete); - MutableConfiguration setProperty(String key, @Nullable T value); + MutableConfiguration setProperty(PropertyKey key, @Nullable T value); - void mergeFrom(Configuration other); + void inheritProperyIfAbsent(PropertyKey key); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java new file mode 100644 index 00000000..f83f2ccf --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java @@ -0,0 +1,9 @@ +package org.sinytra.adapter.next.pipeline.config; + +import org.jetbrains.annotations.Nullable; + +public interface MutablePropertyContainer extends PropertyContainer { + MutablePropertyContainer setProperty(PropertyKey key, @Nullable T value); + + MutablePropertyContainer mergeFrom(PropertyContainer other); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainer.java new file mode 100644 index 00000000..0f4d5157 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainer.java @@ -0,0 +1,16 @@ +package org.sinytra.adapter.next.pipeline.config; + +import java.util.Map; +import java.util.Optional; + +public interface PropertyContainer { + boolean hasProperty(PropertyKey key); + + Optional getProperty(PropertyKey key); + + Map, Object> getProperties(); + + MutablePropertyContainer copy(); + + boolean validate(); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java new file mode 100644 index 00000000..3cbf189a --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java @@ -0,0 +1,65 @@ +package org.sinytra.adapter.next.pipeline.config; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +public class PropertyContainerTemplate { + private final List constraints; + + public PropertyContainerTemplate(List constraints) { + this.constraints = constraints; + } + + public boolean validate(PropertyContainer container) { + for (Validator constraint : this.constraints) { + if (!constraint.validate(container)) { + return false; + } + } + return true; + } + + public Builder extend() { + return new Builder(this.constraints); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final List constraints; + + public Builder() { + this.constraints = new ArrayList<>(); + } + + public Builder(List constraints) { + this.constraints = new ArrayList<>(constraints); + } + + public Builder require(PropertyKey... keys) { + return addConstraint(c -> Stream.of(keys).allMatch(c::hasProperty)); + } + + public Builder requireOne(PropertyKey... keys) { + return addConstraint(c -> Stream.of(keys) + .filter(c::hasProperty) + .count() == 1); + } + + public Builder addConstraint(Validator validator) { + this.constraints.add(validator); + return this; + } + + public PropertyContainerTemplate build() { + return new PropertyContainerTemplate(this.constraints); + } + } + + public interface Validator { + boolean validate(PropertyContainer container); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java new file mode 100644 index 00000000..35fbeb29 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java @@ -0,0 +1,28 @@ +package org.sinytra.adapter.next.pipeline.config; + +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.function.Predicate; + +public class PropertyKey { + private final String name; + private final Predicate predicate; + + public PropertyKey(String name) { + this(name, null); + } + + public PropertyKey(String name, @Nullable Predicate predicate) { + this.name = Objects.requireNonNull(name); + this.predicate = Objects.requireNonNullElseGet(predicate, () -> x -> true); + } + + public boolean validate(T value) { + return this.predicate.test(value); + } + + public String name() { + return this.name; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java index bc3e3847..0062d012 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java @@ -2,26 +2,26 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinData; -import org.sinytra.adapter.next.env.ann.SliceData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_ORDINAL; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; +import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.ORDINAL; +import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.SLICE; public class PropertyProcessor implements Processor { @Override public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { if (dirty.getAtData() == null) return TxResult.FAIL; + // TODO Auto append all props AnnotationHandle handle = context.methodAnnotation(); - dirty.getProperty(PROPERTY_ORDINAL) - .ifPresent(o -> handle.setOrAppendNonNull(PROPERTY_ORDINAL, o)); + dirty.getProperty(ORDINAL) + .ifPresent(o -> handle.setOrAppendNonNull(ORDINAL.name(), o)); - dirty.getProperty(PROPERTY_SLICE) - .ifPresent(s -> handle.setOrAppendNonNull(PROPERTY_SLICE, s.toAnnotationNode())); + dirty.getProperty(SLICE) + .ifPresent(s -> handle.setOrAppendNonNull(SLICE.name(), s.toAnnotationNode())); return TxResult.SUCCESS; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java index 3b684e51..311141a6 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java @@ -19,7 +19,7 @@ import java.util.List; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_STORE; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_ORDINAL; +import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.ORDINAL; public class ModifyVarInjectionPointSubResolver implements SubResolver { @@ -61,7 +61,7 @@ private static Configuration findComparableReplacement(ModifyVariableMixinData m int dirtyOrdinal = dirtyLookup.getOrdinal(lvs.getFirst()); return dirty.subConfig() - .setProperty(PROPERTY_ORDINAL, dirtyOrdinal) + .setProperty(ORDINAL, dirtyOrdinal) .setTargetMethod(method) .inheritAtData(); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java index 8d68d8f8..fe33f989 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java @@ -27,13 +27,14 @@ import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; +import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.SLICE; public class SliceBoundaryResolver implements Resolver { @Override public ResolutionResult resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); - SliceData slice = clean.getProperty(PROPERTY_SLICE).orElse(null); + SliceData slice = clean.getProperty(SLICE).orElse(null); if (slice == null || passesSliceCheck(slice, context, dirtyTarget)) return ResolutionResult.pass(); @@ -42,7 +43,7 @@ public ResolutionResult resolve(MixinData mixin, MixinContext context, Configura return ResolutionResult.pass(); Configuration patch = MutableConfiguration.create() - .setProperty(PROPERTY_SLICE, fixedSlice); + .setProperty(SLICE, fixedSlice); return ResolutionResult.success(patch); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java index c64d51e3..68a1415f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java @@ -1,6 +1,7 @@ package org.sinytra.adapter.next.type; import org.objectweb.asm.Type; +import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; @@ -10,6 +11,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; @@ -22,6 +24,11 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; public class InjectMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return ConfigurationTemplates.MIXIN_AT; + } + @Override public InjectMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { List slice = handle.getNestedList(PROPERTY_SLICE).stream() diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java b/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java index 22806140..c2a6e653 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java @@ -7,6 +7,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -14,6 +15,8 @@ * Handles configuration and behavior specific to a Mixin type */ public interface MixinType { + PropertyContainerTemplate getConfigurationTemplate(); + T parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle); // TODO Return success flag diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java index f8548204..7d7fd1b8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; +import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; @@ -10,6 +11,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; @@ -19,10 +21,15 @@ import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_INDEX; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; +import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.INDEX; public class ModifyArgMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return ConfigurationTemplates.MIXIN_AT; + } + @Override public ModifyArgMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { Integer index = handle.getValue("index").map(AnnotationValueHandle::get).orElse(null); @@ -34,7 +41,7 @@ public void preProcess(ModifyArgMixinData mixin, MixinContext context, MutableCo recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ArbitraryInjectionPointSubResolver()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY))); - mixin.index().ifPresent(i -> clean.setProperty(PROPERTY_INDEX, i)); + mixin.index().ifPresent(i -> clean.setProperty(INDEX, i)); } @Override @@ -45,8 +52,8 @@ public void postProcess(ModifyArgMixinData mixin, MixinContext context, Configur return; } - if (clean.hasProperty(PROPERTY_INDEX) && !dirty.hasProperty(PROPERTY_INDEX)) { - dirty.setProperty(PROPERTY_INDEX, clean.getProperty(PROPERTY_INDEX).orElseThrow()); + if (clean.hasProperty(INDEX) && !dirty.hasProperty(INDEX)) { + dirty.setProperty(INDEX, clean.getProperty(INDEX).orElseThrow()); } Type type = findArgType(context, recipe.clean().getAtData(), dirty.getAtData(), dirty); @@ -66,8 +73,8 @@ private static Type findArgType(MixinContext context, AtData cleanAtData, AtData List cleanArgs = MethodParameters.getParameterTypes(cleanQualifier.desc()); List dirtyArgs = MethodParameters.getParameterTypes(dirtyQualifier.desc()); - if (dirty.hasProperty(PROPERTY_INDEX)) { - int dirtyIndex = dirty.getProperty(PROPERTY_INDEX).orElseThrow(); + if (dirty.hasProperty(INDEX)) { + int dirtyIndex = dirty.getProperty(INDEX).orElseThrow(); return dirtyIndex < dirtyArgs.size() ? dirtyArgs.get(dirtyIndex) : null; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java index 5b32e63f..d0e71fbf 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java @@ -1,6 +1,7 @@ package org.sinytra.adapter.next.type; import org.objectweb.asm.Type; +import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; @@ -9,6 +10,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; @@ -21,6 +23,11 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; public class ModifyExpressionValueMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return ConfigurationTemplates.MIXIN_AT; + } + @Override public ModifyExpressionValueMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { return new ModifyExpressionValueMixinData(targetClass, targetMethod, atData); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java index 2ff670a5..a0c8db1f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java @@ -1,6 +1,7 @@ package org.sinytra.adapter.next.type; import org.objectweb.asm.Type; +import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; @@ -10,6 +11,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.ModifyVarInjectionPointSubResolver; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; @@ -23,8 +25,13 @@ import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.LOCALS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; +import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.SLICE; public class ModifyVariableMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return ConfigurationTemplates.MIXIN_AT; + } @Override public ModifyVariableMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { @@ -39,14 +46,14 @@ public ModifyVariableMixinData parse(MixinContext context, ClassTarget targetCla @Override public void preProcess(ModifyVariableMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, LOCALS))); - clean.setProperty(PROPERTY_SLICE, mixin.slice()); + clean.setProperty(SLICE, mixin.slice()); recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ModifyVarInjectionPointSubResolver()); } @Override public void postProcess(ModifyVariableMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - dirty.inheritProperyIfAbsent(PROPERTY_SLICE); + dirty.inheritProperyIfAbsent(SLICE); if (mixin.argsOnly() && dirty.getTargetMethod() != null && !dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { Type cleanVarType = clean.getParameters().get(SINGLE_ANY).getFirst(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java index 4fb00ba9..95b418bd 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java @@ -1,6 +1,7 @@ package org.sinytra.adapter.next.type; import org.objectweb.asm.Type; +import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; @@ -10,6 +11,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.processor.ParameterUsageProcessor; import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; @@ -24,6 +26,11 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; public class RedirectMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return ConfigurationTemplates.MIXIN_AT; + } + @Override public RedirectMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { return new RedirectMixinData(targetClass, targetMethod, atData); @@ -58,7 +65,7 @@ public void postProcess(RedirectMixinData mixin, MixinContext context, Configura MethodQualifier targetDesc = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); if (targetDesc == null) return; - + List dirtyCaptured = context.methods().resolveCapturedMethodParams(recipe.clean(), recipe.dirty()); List callTypes = MethodParameters.getParameterTypes(targetDesc.desc()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java index 29c8b271..f8daa6ec 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java @@ -2,6 +2,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; @@ -11,6 +12,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; @@ -23,6 +25,11 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; public class WrapOperationMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return ConfigurationTemplates.MIXIN_AT; + } + @Override public WrapOperationMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { return new WrapOperationMixinData(targetClass, targetMethod, atData); diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java index 60c89781..dfe3ee24 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/CrossbowAttackGoalMixin.java @@ -2,13 +2,16 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.LivingEntity; +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 net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.item.Item; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -16,6 +19,14 @@ @Mixin(RangedCrossbowAttackGoal.class) public abstract class CrossbowAttackGoalMixin extends Goal { + @Shadow + @Final + private T mob; + + @Shadow + @Final + private Mob mobExpected; + // https://github.com/SolipIngen/minecraft.progressivearchery/blob/7af8bdb7ddc24d73163d17de082add89716755cb/src/main/java/solipingen/progressivearchery/mixin/entity/ai/goal/CrossbowAttackGoalMixin.java#L42 @Redirect( method = "tick()V", From fe3ba03084a2659dbcf41c310b734397304692a5 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Fri, 16 Jan 2026 17:03:46 +0100 Subject: [PATCH 05/27] Migrate dynamic fixers to transformation pipeline --- .../adapter/patch/ClassPatchInstance.java | 7 +- .../patch/analysis/InheritanceHandler.java | 16 +- .../patch/analysis/MethodCallAnalyzer.java | 330 ---------------- .../analysis/locals/LocalVariableLookup.java | 4 + .../patch/analysis/method/MethodAnalyzer.java | 171 +++++++++ .../analysis/method/MethodCallAnalyzer.java | 124 ++++++ .../analysis/method/MethodInsnMatcher.java | 81 ++++ .../analysis/params/EnhancedParamsDiff.java | 65 ++-- .../params/LayeredParamsDiffSnapshot.java | 20 +- .../analysis/params/ParamsDiffSnapshot.java | 6 +- .../analysis/selector/AnnotationHandle.java | 12 +- .../patch/analysis/selector/FrameUtil.java | 69 ++++ .../patch/api/MethodTransformBuilder.java | 5 - .../patch/api/MethodTransformFilter.java | 5 - .../adapter/patch/api/MixinConstants.java | 7 + .../fixes/FieldTypeUsageTransformer.java | 6 +- .../patch/transformer/MethodUpgrader.java | 187 --------- .../ModifyArgsOffsetTransformer.java | 53 --- .../transformer/ModifyArgsOffsetUpgrader.java | 37 ++ .../DynamicInheritedInjectionPointPatch.java | 3 +- .../dynamic/DynamicInjectorOrdinalPatch.java | 10 +- .../transformer/dynamic/DynamicLVTPatch.java | 1 - .../DynamicModifyVarAtReturnPatch.java | 7 +- .../LocalCaptureUpgradePreprocessor.java} | 39 +- .../dynfix/DynFixMethodComparison.java | 359 ------------------ .../transformer/dynfix/DynamicFixer.java | 33 -- .../dynfix/DynamicInjectionPointPatch.java | 62 --- .../dynfix/WrapOperationSurgeon.java | 181 --------- .../operation/CompoundMethodTransform.java | 104 ----- .../param/InjectParameterTransform.java | 17 +- .../param/ParamTransformationUtil.java | 226 +---------- .../param/RemoveParameterTransformer.java | 13 +- .../param/ReplaceParametersTransformer.java | 22 +- .../operation/unit/ExtractMixin.java | 3 +- .../operation/unit/ModifyInjectionPoint.java | 23 +- .../operation/unit/ModifyInjectionTarget.java | 41 +- .../adapter/patch/util/AdapterUtil.java | 96 +++-- .../util/MethodTransformBuilderImpl.java | 22 +- .../next/PipelineLegacyMethodTransformer.java | 4 +- .../next/env/ConfigurationTemplates.java | 3 + .../adapter/next/env/Configurations.java | 9 + .../adapter/next/env/MixinContext.java | 16 +- .../sinytra/adapter/next/env/ann/AtData.java | 10 +- .../adapter/next/env/ann/ConstantData.java | 24 ++ .../adapter/next/env/ann/InjectMixinData.java | 20 - .../env/ann/MixinAnnotationConstants.java | 3 +- .../adapter/next/env/ann/MixinData.java | 19 +- .../next/env/ann/ModifyArgMixinData.java | 19 - .../ann/ModifyExpressionValueMixinData.java | 9 - .../next/env/ann/ModifyVariableMixinData.java | 34 -- .../next/env/ann/RedirectMixinData.java | 9 - .../adapter/next/env/ann/SliceData.java | 6 +- .../next/env/ann/WrapOperationMixinData.java | 9 - .../adapter/next/env/ctx/MethodFinder.java | 18 + .../adapter/next/env/ctx/MethodHelper.java | 34 +- .../adapter/next/env/ctx/RefMapper.java | 5 + .../adapter/next/env/param/Annotation.java | 79 ++++ .../adapter/next/env/param/Copiable.java | 5 + .../next/env/param/MethodParameters.java | 126 ++++-- .../adapter/next/env/param/Parameter.java | 72 ++++ .../adapter/next/env/param/Parameters.java | 125 ++++++ .../next/pipeline/PipelineExecutor.java | 69 +++- .../sinytra/adapter/next/pipeline/Recipe.java | 20 +- .../config/BasePropertyContainer.java | 6 + .../next/pipeline/config/Configuration.java | 50 ++- .../pipeline/config/ConfigurationImpl.java | 19 +- .../pipeline/config/MutableConfiguration.java | 15 +- .../config/MutablePropertyContainer.java | 1 + .../config/PropertyContainerTemplate.java | 6 +- .../next/pipeline/config/PropertyKey.java | 65 +++- .../processor/InjectionTargetProcessor.java | 25 +- .../processor/ParameterUsageProcessor.java | 5 - .../processor/ParametersProcessor.java | 50 ++- .../next/pipeline/processor/Processors.java | 2 + .../processor/ReturnTypeProcessor.java | 10 +- .../processor/TargetMethodProcessor.java | 23 ++ .../extract/ExtractMixinProcessor.java | 29 ++ .../extract}/MirrorableExtractMixin.java | 19 +- .../processor/wrapop/WrapOpAnalyzer.java | 95 +++++ .../wrapop/WrapOpParamsProcessor.java | 173 +++++++++ .../processor/wrapop/WrapOpSurgeon.java | 146 +++++++ .../pipeline/resolver/CompoundResolver.java | 21 +- .../next/pipeline/resolver/Resolver.java | 8 +- .../next/pipeline/resolver/SubResolver.java | 2 +- .../ArbitraryInjectionPointSubResolver.java | 16 +- .../AtVariableAssignStoreSubResolver.java | 10 +- .../ComparingInjectionPointResolver.java | 250 ++++++++++++ .../injection/InjectionPointResolver.java | 15 +- .../injection/InjectionPointSubResolvers.java | 28 +- .../ModifyVarInjectionPointSubResolver.java | 23 +- .../special/ResolverSyntheticInstanceof.java | 28 +- .../special/SliceBoundaryResolver.java | 7 +- .../SplitMethodCancellationHelper.java | 38 +- .../target/SplitTargetMethodSubResolver.java | 78 ++-- .../resolver/target/TargetMethodResolver.java | 17 +- .../target/TargetMethodSubResolvers.java | 21 +- .../adapter/next/type/InjectMixin.java | 62 +-- .../sinytra/adapter/next/type/MixinType.java | 18 +- .../sinytra/adapter/next/type/MixinTypes.java | 19 +- .../adapter/next/type/ModifyArgMixin.java | 40 +- .../next/type/ModifyExpressionValueMixin.java | 34 +- .../next/type/ModifyVariableMixin.java | 58 +-- .../adapter/next/type/RedirectMixin.java | 47 +-- .../adapter/next/type/WrapOperationMixin.java | 52 ++- .../patch/test/EnhancedParamsDiffTest.java | 35 ++ .../test/mixin/DynamicMixinPatchTest.java | 4 +- .../adapter/test/mixin/BoatRendererMixin.java | 16 +- .../adapter/test/mixin/PiglinAiMixin.java | 16 +- .../adapter/test/mixin/PumpkinBlockMixin.java | 16 +- .../adapter/test/mixin/StemBlockMixin.java | 4 +- .../test/mixin/TripWireBlockMixin.java | 16 +- .../test/mixin/pipeline/CropBlockMixin.java | 8 +- 112 files changed, 2635 insertions(+), 2325 deletions(-) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodCallAnalyzer.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodInsnMatcher.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FrameUtil.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformFilter.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/MethodUpgrader.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetTransformer.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetUpgrader.java rename definition/src/main/java/org/sinytra/adapter/patch/transformer/{dynfix/DynFixLocalCaptureUpgrade.java => dynamic/LocalCaptureUpgradePreprocessor.java} (69%) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixMethodComparison.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicFixer.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicInjectionPointPatch.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/WrapOperationSurgeon.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/CompoundMethodTransform.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/InjectMixinData.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyArgMixinData.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyExpressionValueMixinData.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/RedirectMixinData.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/WrapOperationMixinData.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefMapper.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/param/Annotation.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/param/Copiable.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/dynfix => next/java/org/sinytra/adapter/next/pipeline/processor/extract}/MirrorableExtractMixin.java (84%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/dynfix => next/java/org/sinytra/adapter/next/pipeline/resolver/target}/SplitMethodCancellationHelper.java (68%) diff --git a/definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java b/definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java index 75784d01..99eb92df 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java @@ -105,12 +105,7 @@ public ClassPatchBuilder targetInjectionPoint(String value, String target) { @Override public ClassPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues) { - return modifyInjectionPoint(value, target, resetValues, false); - } - - @Override - public ClassPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues, boolean dontUpgrade) { - return transform(new ModifyInjectionPoint(value, target, resetValues, dontUpgrade)); + return transform(new ModifyInjectionPoint(value, target, resetValues)); } @Override diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java index bad0d15f..9cb58862 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java @@ -24,21 +24,7 @@ public boolean isClassInherited(String child, String parent) { return childNode != null && parentNode != null && getClassParents(child).contains(parent); } - public boolean isMethodOverriden(String cls, String name, String desc) { - for (String parent : getClassParents(cls)) { - ClassNode node = this.classProvider.getClass(parent).orElse(null); - if (node != null) { - for (MethodNode method : node.methods) { - if (method.name.equals(name) && method.desc.equals(desc) && (method.access & Opcodes.ACC_PRIVATE) == 0 && (method.access & Opcodes.ACC_FINAL) == 0) { - return true; - } - } - } - } - return false; - } - - private Collection getClassParents(String name) { + public Collection getClassParents(String name) { Collection parents = this.parentCache.get(name); if (parents == null) { parents = computeClassParents(name); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodCallAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodCallAnalyzer.java deleted file mode 100644 index 6543c2ad..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodCallAnalyzer.java +++ /dev/null @@ -1,330 +0,0 @@ -package org.sinytra.adapter.patch.analysis; - -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.objectweb.asm.tree.analysis.*; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.OpcodeUtil; - -import java.util.*; -import java.util.function.BiPredicate; -import java.util.function.UnaryOperator; -import java.util.stream.Stream; - -public class MethodCallAnalyzer { - public static final UnaryOperator FORWARD = AbstractInsnNode::getNext; - public static final UnaryOperator BACKWARDS = AbstractInsnNode::getPrevious; - public static final String LAMBDA_PREFIX = "lambda$"; - private static final int INSN_RANGE = 5; - - public static boolean isDirtyDeprecatedMethod(MethodNode clean, MethodNode dirty) { - return !AdapterUtil.hasAnnotation(clean.visibleAnnotations, MixinConstants.DEPRECATED) && AdapterUtil.hasAnnotation(dirty.visibleAnnotations, MixinConstants.DEPRECATED); - } - - @Nullable - public static List collectMethodInvocations(ClassNode cls, MethodNode mtd) { - // Iterate over isns, leave out first and last elements - // Collect method invocations - // All labels must be finalized by a method invocation to pass - List invocations = new ArrayList<>(); - for (int i = 1; i < mtd.instructions.size(); i++) { - AbstractInsnNode insn = mtd.instructions.get(i); - if (insn instanceof LabelNode) { - AbstractInsnNode previous = insn.getPrevious(); - AbstractInsnNode effectivePrevious = previous; - if (OpcodeUtil.isReturnOpcode(previous.getOpcode())) { - effectivePrevious = previous.getPrevious(); - } - - if (effectivePrevious instanceof MethodInsnNode methodInsn && methodInsn.owner.equals(cls.name)) { - cls.methods.stream() - .filter(m -> m.name.equals(methodInsn.name) && m.desc.equals(methodInsn.desc)) - .findFirst() - .ifPresent(invocations::add); - } else if (previous == null || !OpcodeUtil.isReturnOpcode(previous.getOpcode())) { - return null; - } - } - } - return invocations; - } - - public static List findLambdasInMethod(ClassNode cls, MethodNode method, @Nullable Multimap methods) { - List list = new ArrayList<>(); - for (AbstractInsnNode insn : method.instructions) { - if (insn instanceof InvokeDynamicInsnNode indy && indy.bsmArgs.length >= 3) { - for (Object bsmArg : indy.bsmArgs) { - if (bsmArg instanceof Handle handle && handle.getOwner().equals(cls.name)) { - if (handle.getName().startsWith(LAMBDA_PREFIX)) { - String name = handle.getName(); - list.add(name); - if (methods != null) { - MethodNode lambda = findUniqueMethod(methods, name); - list.addAll(findLambdasInMethod(cls, lambda, methods)); - } - break; - } - } - } - } - } - return list; - } - - public static Optional findMethodByUniqueName(ClassNode cls, String name) { - List methods = cls.methods.stream().filter(m -> m.name.equals(name)).toList(); - if (methods.size() != 1) { - return Optional.empty(); - } - return Optional.of(methods.getFirst()); - } - - public static Optional findMethodByName(ClassNode cls, String name, @Nullable String desc) { - return cls.methods.stream() - .filter(m -> m.name.equals(name) && (desc == null || m.desc.equals(desc))) - .findFirst(); - } - - public static Multimap getMethodCalls(MethodNode node, List callOrder) { - ImmutableMultimap.Builder calls = ImmutableMultimap.builder(); - for (AbstractInsnNode insn : node.instructions) { - if (insn instanceof MethodInsnNode minsn) { - String qualifier = getCallQualifier(minsn); - calls.put(qualifier, minsn); - callOrder.add(qualifier); - } - } - return calls.build(); - } - - public static InstructionMatcher findSurroundingInstructions(AbstractInsnNode insn) { - return findSurroundingInstructions(insn, INSN_RANGE); - } - - public static InstructionMatcher findSurroundingInstructions(AbstractInsnNode insn, int range) { - LabelNode previousLabel = findFirstInsn(insn, LabelNode.class, BACKWARDS); - LabelNode nextLabel = findFirstInsn(insn, LabelNode.class, FORWARD); - - List previousInsns = getInsns(previousLabel, range, BACKWARDS); - List nextInsns = getInsns(nextLabel, range, FORWARD); - - return new InstructionMatcher(insn, previousInsns, nextInsns); - } - - public static InstructionMatcher findBackwardsInstructions(AbstractInsnNode insn) { - return findBackwardsInstructions(insn, INSN_RANGE); - } - - public static InstructionMatcher findBackwardsInstructions(AbstractInsnNode insn, int range) { - LabelNode previousLabel = findFirstInsn(insn, LabelNode.class, BACKWARDS); - List previousInsns = getInsns(previousLabel, range, BACKWARDS); - - return new InstructionMatcher(insn, previousInsns, List.of()); - } - - public static InstructionMatcher findForwardInstructions(AbstractInsnNode insn) { - return findForwardInstructions(insn, INSN_RANGE); - } - - public static InstructionMatcher findForwardInstructions(AbstractInsnNode insn, int range) { - LabelNode nextLabel = findFirstInsn(insn, LabelNode.class, FORWARD); - List nextInsns = getInsns(nextLabel, range, FORWARD); - - return new InstructionMatcher(insn, List.of(), nextInsns); - } - - public static InstructionMatcher findForwardInstructionsDirect(AbstractInsnNode insn) { - return findForwardInstructionsDirect(insn, INSN_RANGE); - } - - public static InstructionMatcher findForwardInstructionsDirect(AbstractInsnNode insn, int range) { - List nextInsns = getInsns(insn, range, FORWARD); - - return new InstructionMatcher(insn, List.of(), nextInsns); - } - - private static List getInsns(AbstractInsnNode root, int range, UnaryOperator operator) { - return Stream.iterate(root, Objects::nonNull, operator) - .filter(insn -> !(insn instanceof FrameNode) && !(insn instanceof LineNumberNode)) - .limit(range) - .toList(); - } - - @SuppressWarnings("unchecked") - @Nullable - public static T findFirstInsn(AbstractInsnNode insn, Class type, UnaryOperator operator) { - return (T) Stream.iterate(insn, Objects::nonNull, operator) - .filter(type::isInstance) - .findFirst() - .orElse(null); - } - - public static String getCallQualifier(MethodInsnNode insn) { - return Type.getObjectType(insn.owner).getDescriptor() + insn.name + insn.desc; - } - - public static boolean containsMethodCall(MethodNode methodNode, MethodQualifier qualifier) { - return !getInvocationInsns(methodNode, qualifier).isEmpty(); - } - - public static List> getInvocationInsns(MethodNode methodNode, MethodQualifier qualifier) { - return analyzeMethod(methodNode, (insn, values) -> qualifier.matches(insn) && values.size() > 1, (insn, values) -> { - List insns = new ArrayList<>(); - for (SourceValue value : values) { - if (value.insns.size() == 1) { - insns.add(value.insns.iterator().next()); - } - } - insns.add(insn); - return insns; - }); - } - - public static int getMethodCallOrdinal(MethodNode method, MethodInsnNode insn) { - List insns = new ArrayList<>(); - for (AbstractInsnNode i : method.instructions) { - if (i instanceof MethodInsnNode m && InsnComparator.insnEqual(m, insn)) { - insns.add(m); - } - } - return insns.indexOf(insn); - } - - public static int getArgIndex(String desc, Type type) { - List args = Arrays.asList(Type.getArgumentTypes(desc)); - List found = args.stream().filter(type::equals).toList(); - if (found.size() != 1) { - return -1; - } - return args.indexOf(found.getFirst()); - } - - @Nullable - public static List findMethodCallParamInsns(MethodNode methodNode, MethodInsnNode insn) { - MethodCallInterpreter interpreter = MethodCallAnalyzer.analyzeInterpretMethod(methodNode, new MethodCallInterpreter(insn)); - return interpreter.getTargetArgs(); - } - - @Nullable - public static List findFullMethodCallParamInsns(MethodNode methodNode, MethodInsnNode minsn) { - List insns = findMethodCallParamInsns(methodNode, minsn); - if (minsn != null) { - List fullInsns = new ArrayList<>(); - for (AbstractInsnNode i = insns.getFirst(); i != null; i = i.getNext()) { - if (i == minsn) { - break; - } - fullInsns.add(i); - } - return fullInsns; - } - return null; - } - - public static List analyzeMethod(MethodNode methodNode, BiPredicate> filter, NaryOperationHandler handler) { - AnalysingSourceInterpreter i = new AnalysingSourceInterpreter<>(filter, handler); - Analyzer analyzer = new Analyzer<>(i); - try { - analyzer.analyze(methodNode.name, methodNode); - } catch (AnalyzerException e) { - throw new RuntimeException(e); - } - return i.getResults(); - } - - public static , V extends Value> T analyzeInterpretMethod(MethodNode methodNode, T interpreter) { - Analyzer analyzer = new Analyzer<>(interpreter); - try { - analyzer.analyze(methodNode.name, methodNode); - } catch (AnalyzerException e) { - throw new RuntimeException(e); - } - return interpreter; - } - - public interface NaryOperationHandler { - T accept(MethodInsnNode insn, List values); - } - - @Nullable - public static AbstractInsnNode getSingleInsn(List values, int index) { - SourceValue value = values.get(index); - return value.insns.size() == 1 ? value.insns.iterator().next() : null; - } - - public static MethodNode findUniqueMethod(Multimap methods, String name) { - Collection values = methods.get(name); - if (values != null && !values.isEmpty()) { - if (values.size() > 1) { - throw new IllegalStateException("Found multiple candidates for method " + name); - } - return values.iterator().next(); - } - throw new NullPointerException("Method " + name + " not found"); - } - - private static class MethodCallInterpreter extends SourceInterpreter { - private final MethodInsnNode targetInsn; - private List targetArgs; - - public MethodCallInterpreter(MethodInsnNode targetInsn) { - super(Opcodes.ASM9); - this.targetInsn = targetInsn; - } - - @javax.annotation.Nullable - public List getTargetArgs() { - return this.targetArgs; - } - - @Override - public SourceValue naryOperation(AbstractInsnNode insn, List values) { - if (insn == this.targetInsn && this.targetArgs == null) { - List targetArgs = values.stream() - .map(v -> v.insns.size() == 1 ? v.insns.iterator().next() : null) - .toList(); - if (!targetArgs.contains(null)) { - this.targetArgs = targetArgs; - } - } - return super.naryOperation(insn, values); - } - } - - private static class AnalysingSourceInterpreter extends SourceInterpreter { - private final BiPredicate> filter; - private final NaryOperationHandler handler; - private final List results = new ArrayList<>(); - private final Collection seen = new HashSet<>(); - - public AnalysingSourceInterpreter(BiPredicate> filter, NaryOperationHandler handler) { - super(Opcodes.ASM9); - - this.filter = filter; - this.handler = handler; - } - - public List getResults() { - return this.results; - } - - @Override - public SourceValue naryOperation(AbstractInsnNode insn, List values) { - if (insn instanceof MethodInsnNode minsn && this.filter.test(minsn, values) && !this.seen.contains(minsn)) { - T result = this.handler.accept(minsn, values); - if (result != null) { - this.results.add(result); - this.seen.add(minsn); - } - } - return super.naryOperation(insn, values); - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java index 0b6fa9d8..9337a0dd 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java @@ -45,6 +45,10 @@ public int getOrdinal(LocalVariableNode node) { return this.sortedLocals.indexOf(node); } + public int getParameterOrdinal(LocalVariableNode node) { + return getOrdinal(node) + (this.isNonStatic ? 1 : 0); + } + public LocalVariableNode getLast() { return this.sortedLocals.getLast(); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java new file mode 100644 index 00000000..cc87ea8e --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java @@ -0,0 +1,171 @@ +package org.sinytra.adapter.patch.analysis.method; + +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.analysis.*; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.patch.util.OpcodeUtil; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.function.BiPredicate; + +public class MethodAnalyzer { + public static final String LAMBDA_PREFIX = "lambda$"; + + public static boolean isDirtyDeprecatedMethod(MethodNode clean, MethodNode dirty) { + return !AdapterUtil.hasAnnotation(clean.visibleAnnotations, MixinConstants.DEPRECATED) && AdapterUtil.hasAnnotation(dirty.visibleAnnotations, MixinConstants.DEPRECATED); + } + + public static List getMethodInvocations(MethodNode method, MethodQualifier qualifier) { + List list = new ArrayList<>(); + for (AbstractInsnNode insn : method.instructions) { + if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { + list.add(minsn); + } + } + return list; + } + + @Nullable + public static List collectMethodInvocations(ClassNode cls, MethodNode mtd) { + // Iterate over isns, leave out first and last elements + // Collect method invocations + // All labels must be finalized by a method invocation to pass + List invocations = new ArrayList<>(); + for (int i = 1; i < mtd.instructions.size(); i++) { + AbstractInsnNode insn = mtd.instructions.get(i); + if (insn instanceof LabelNode) { + AbstractInsnNode previous = insn.getPrevious(); + AbstractInsnNode effectivePrevious = previous; + if (OpcodeUtil.isReturnOpcode(previous.getOpcode())) { + effectivePrevious = previous.getPrevious(); + } + + if (effectivePrevious instanceof MethodInsnNode methodInsn && methodInsn.owner.equals(cls.name)) { + cls.methods.stream() + .filter(m -> m.name.equals(methodInsn.name) && m.desc.equals(methodInsn.desc)) + .findFirst() + .ifPresent(invocations::add); + } else if (previous == null || !OpcodeUtil.isReturnOpcode(previous.getOpcode())) { + return null; + } + } + } + return invocations; + } + + public static List findLambdasInMethod(ClassNode cls, MethodNode method, @Nullable Multimap methods) { + List list = new ArrayList<>(); + for (AbstractInsnNode insn : method.instructions) { + if (insn instanceof InvokeDynamicInsnNode indy && indy.bsmArgs.length >= 3) { + for (Object bsmArg : indy.bsmArgs) { + if (bsmArg instanceof Handle handle && handle.getOwner().equals(cls.name)) { + if (handle.getName().startsWith(LAMBDA_PREFIX)) { + String name = handle.getName(); + list.add(name); + if (methods != null) { + MethodNode lambda = findUniqueMethod(methods, name); + if (lambda != null) { + list.addAll(findLambdasInMethod(cls, lambda, methods)); + } + } + break; + } + } + } + } + } + return list; + } + + public static Multimap getMethodCalls(MethodNode node, List callOrder) { + ImmutableMultimap.Builder calls = ImmutableMultimap.builder(); + for (AbstractInsnNode insn : node.instructions) { + if (insn instanceof MethodInsnNode minsn) { + String qualifier = MethodQualifier.create(minsn).asDescriptor(); + calls.put(qualifier, minsn); + callOrder.add(qualifier); + } + } + return calls.build(); + } + + public static boolean containsMethodCall(MethodNode methodNode, MethodQualifier qualifier) { + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { + return true; + } + } + return false; + } + + public static List analyzeMethod(MethodNode methodNode, BiPredicate> filter, NaryOperationHandler handler) { + AnalysingSourceInterpreter i = analyzeInterpretMethod(methodNode, new AnalysingSourceInterpreter<>(filter, handler)); + return i.getResults(); + } + + public static , V extends Value> T analyzeInterpretMethod(MethodNode methodNode, T interpreter) { + Analyzer analyzer = new Analyzer<>(interpreter); + try { + analyzer.analyze(methodNode.name, methodNode); + } catch (AnalyzerException e) { + throw new RuntimeException(e); + } + return interpreter; + } + + @Nullable + private static MethodNode findUniqueMethod(Multimap methods, String name) { + Collection values = methods.get(name); + if (values != null && !values.isEmpty()) { + if (values.size() > 1) { + return null; + } + return values.iterator().next(); + } + return null; + } + + public interface NaryOperationHandler { + T accept(MethodInsnNode insn, List values); + } + + private static class AnalysingSourceInterpreter extends SourceInterpreter { + private final BiPredicate> filter; + private final NaryOperationHandler handler; + private final List results = new ArrayList<>(); + private final Collection seen = new HashSet<>(); + + public AnalysingSourceInterpreter(BiPredicate> filter, NaryOperationHandler handler) { + super(Opcodes.ASM9); + + this.filter = filter; + this.handler = handler; + } + + public List getResults() { + return this.results; + } + + @Override + public SourceValue naryOperation(AbstractInsnNode insn, List values) { + if (insn instanceof MethodInsnNode minsn && this.filter.test(minsn, values) && !this.seen.contains(minsn)) { + T result = this.handler.accept(minsn, values); + if (result != null) { + this.results.add(result); + this.seen.add(minsn); + } + } + return super.naryOperation(insn, values); + } + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java new file mode 100644 index 00000000..0fe0c1d0 --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java @@ -0,0 +1,124 @@ +package org.sinytra.adapter.patch.analysis.method; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.SourceInterpreter; +import org.objectweb.asm.tree.analysis.SourceValue; +import org.sinytra.adapter.patch.analysis.selector.FrameUtil; +import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.MethodQualifier; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class MethodCallAnalyzer { + @Nullable + public static List getMethodCallInsns(MethodNode methodNode, MethodInsnNode minsn) { + return Optional.ofNullable(getMethodCallSrcInsns(methodNode, minsn)) + .filter(insns -> !insns.isEmpty()) + .map(insns -> { + AbstractInsnNode start = insns.getFirst(); + return AdapterUtil.subListInsnsExc(start, minsn); + }) + .orElse(null); + } + + public static List> getAllMethodCallSrcInsnsInclusive(MethodNode methodNode, MethodQualifier qualifier) { + List> list = new ArrayList<>(); + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { + List insns = getMethodCallSrcInsns(methodNode, minsn); + insns.add(minsn); + if (insns != null) { + list.add(insns); + } + } + } + return list; + } + + @Nullable + public static List getMethodCallSrcInsns(MethodNode methodNode, MethodInsnNode minsn) { + List sources = getCallSourceValues(methodNode, minsn); + List insns = new ArrayList<>(); + for (SourceValue src : sources) { + AbstractInsnNode srcInsn = AdapterUtil.getSingleInsn(src); + if (srcInsn == null) { + return null; + } + insns.add(srcInsn); + } + return insns; + } + + public static List> getMethodCallArgInsns(MethodNode methodNode, MethodInsnNode minsn) { + Frame[] frames = FrameUtil.getFrames(methodNode); + Frame frame = frames[methodNode.instructions.indexOf(minsn)]; + + List> args = new ArrayList<>(); + for (int i = 0; i < frame.getStackSize(); ++i) { + List insns = new ArrayList<>(); + SourceValue value = frame.getStack(i); + for (AbstractInsnNode insn : value.insns) { + expandArgInitInsnsRecursive(insns, methodNode.instructions, frames, insn); + insns.add(insn); + } + args.add(insns); + } + return args; + } + + private static void expandArgInitInsnsRecursive(List out, InsnList insns, Frame[] frames, AbstractInsnNode insn) { + int index = insns.indexOf(insn); + if (index < 0 || index >= frames.length || frames[index] == null) return; + + Frame frame = frames[index]; + int inputs = FrameUtil.getPopCount(insn); + int stackSize = frame.getStackSize(); + int start = stackSize - inputs; + + for (int i = start; i < stackSize; ++i) { + SourceValue value = frame.getStack(i); + for (AbstractInsnNode sourceInsn : value.insns) { + if (!out.contains(sourceInsn)) { + expandArgInitInsnsRecursive(out, insns, frames, sourceInsn); + out.add(sourceInsn); + } + } + } + } + + @Nullable + public static List getCallSourceValues(MethodNode methodNode, MethodInsnNode minsn) { + SourceValueInterpreter i = MethodAnalyzer.analyzeInterpretMethod(methodNode, new SourceValueInterpreter(minsn)); + return i.getResults(); + } + + private static class SourceValueInterpreter extends SourceInterpreter { + private final AbstractInsnNode targetInsn; + private List results; + + public SourceValueInterpreter(AbstractInsnNode targetInsn) { + super(Opcodes.ASM9); + this.targetInsn = targetInsn; + } + + public List getResults() { + return this.results; + } + + @Override + public SourceValue naryOperation(AbstractInsnNode insn, List values) { + if (insn == this.targetInsn && this.results == null) { + this.results = values; + } + return super.naryOperation(insn, values); + } + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodInsnMatcher.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodInsnMatcher.java new file mode 100644 index 00000000..c7b3aa3b --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodInsnMatcher.java @@ -0,0 +1,81 @@ +package org.sinytra.adapter.patch.analysis.method; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FrameNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.sinytra.adapter.patch.analysis.InstructionMatcher; + +import java.util.List; +import java.util.Objects; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +public class MethodInsnMatcher { + public static final UnaryOperator FORWARD = AbstractInsnNode::getNext; + public static final UnaryOperator BACKWARDS = AbstractInsnNode::getPrevious; + private static final int INSN_RANGE = 5; + + public static InstructionMatcher findSurroundingInstructions(AbstractInsnNode insn) { + return findSurroundingInstructions(insn, INSN_RANGE); + } + + public static InstructionMatcher findSurroundingInstructions(AbstractInsnNode insn, int range) { + LabelNode previousLabel = findFirstLabelInsn(insn, BACKWARDS); + LabelNode nextLabel = findFirstLabelInsn(insn, FORWARD); + + List previousInsns = getInsns(previousLabel, range, BACKWARDS); + List nextInsns = getInsns(nextLabel, range, FORWARD); + + return new InstructionMatcher(insn, previousInsns, nextInsns); + } + + public static InstructionMatcher findBackwardsInstructions(AbstractInsnNode insn) { + return findBackwardsInstructions(insn, INSN_RANGE); + } + + public static InstructionMatcher findBackwardsInstructions(AbstractInsnNode insn, int range) { + LabelNode previousLabel = findFirstLabelInsn(insn, BACKWARDS); + List previousInsns = getInsns(previousLabel, range, BACKWARDS); + + return new InstructionMatcher(insn, previousInsns, List.of()); + } + + public static InstructionMatcher findForwardInstructions(AbstractInsnNode insn) { + return findForwardInstructions(insn, INSN_RANGE); + } + + public static InstructionMatcher findForwardInstructions(AbstractInsnNode insn, int range) { + LabelNode nextLabel = findFirstLabelInsn(insn, FORWARD); + List nextInsns = getInsns(nextLabel, range, FORWARD); + + return new InstructionMatcher(insn, List.of(), nextInsns); + } + + public static InstructionMatcher findForwardInstructionsDirect(AbstractInsnNode insn) { + return findForwardInstructionsDirect(insn, INSN_RANGE); + } + + public static InstructionMatcher findForwardInstructionsDirect(AbstractInsnNode insn, int range) { + List nextInsns = getInsns(insn, range, FORWARD); + + return new InstructionMatcher(insn, List.of(), nextInsns); + } + + @Nullable + private static LabelNode findFirstLabelInsn(AbstractInsnNode insn, UnaryOperator operator) { + return Stream.iterate(insn, Objects::nonNull, operator) + .filter(LabelNode.class::isInstance) + .map(LabelNode.class::cast) + .findFirst() + .orElse(null); + } + + private static List getInsns(AbstractInsnNode root, int range, UnaryOperator operator) { + return Stream.iterate(root, Objects::nonNull, operator) + .filter(insn -> !(insn instanceof FrameNode) && !(insn instanceof LineNumberNode)) + .limit(range) + .toList(); + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java index f164d523..f5248bcd 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java @@ -2,6 +2,7 @@ import com.google.common.collect.MapDifference; import com.google.common.collect.Maps; +import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; @@ -20,6 +21,7 @@ public class EnhancedParamsDiff { public static LayeredParamsDiffSnapshot createLayered(List clean, List dirty) { LayeredParamsDiffSnapshot.Builder builder = LayeredParamsDiffSnapshot.builder(); buildDiff(builder, clean, dirty); + // TODO Sanity check return builder.build(); } @@ -258,6 +260,26 @@ private static boolean isPossiblyInjected(int index, List clean private record SwapResult(List removeDirty) { } + + private static Comparator maybeInverse(Comparator comparator, boolean inverse) { + return inverse ? comparator.reversed() : comparator; + } + + private static List> sortMapDiff(Map map, List context, boolean descending) { + return map.entrySet().stream() + .map(e -> { + Type type = e.getKey(); + Integer count = e.getValue(); + if (count == 1) { + TypeWithContext inserted = context.stream().filter(t -> t.type().equals(type)).findFirst().orElseThrow(); + return Pair.of(type, inserted); + } + return null; + }) + .filter(Objects::nonNull) + .sorted(maybeInverse(Comparator.comparingInt(p -> p.getSecond().pos()), descending)) + .toList(); + } @Nullable private static SwapResult checkForSwaps(ParamsDiffSnapshotBuilder builder, List clean, List dirty) { @@ -271,32 +293,27 @@ private static SwapResult checkForSwaps(ParamsDiffSnapshotBuilder builder, List< LayeredParamsDiffSnapshot.Builder tempDiff = LayeredParamsDiffSnapshot.builder(); // Remove inserted parameters if (diff.entriesOnlyOnLeft().isEmpty() && !diff.entriesOnlyOnRight().isEmpty()) { - for (Map.Entry entry : diff.entriesOnlyOnRight().entrySet()) { - Type type = entry.getKey(); - Integer count = entry.getValue(); - if (count == 1) { - TypeWithContext inserted = dirty.stream().filter(t -> t.type().equals(type)).findFirst().orElseThrow(); - dirtyGroup.remove(type); - rearrangeDirty.remove(inserted); - removeDirty.add(inserted); - int offset = inserted.pos() + (int) builder.getRemovals().stream().filter(i -> i < inserted.pos()).count(); - tempDiff.insert(offset, inserted.type()); - } + // Sort by insertion order first + for (Pair p : sortMapDiff(diff.entriesOnlyOnRight(), dirty, false)) { + Type type = p.getFirst(); + TypeWithContext inserted = p.getSecond(); + + dirtyGroup.remove(type); + rearrangeDirty.remove(inserted); + removeDirty.add(inserted); + int offset = inserted.pos() + (int) builder.getRemovals().stream().filter(i -> i < inserted.pos()).count(); + tempDiff.insert(offset, inserted.type()); } } else if (!diff.entriesOnlyOnLeft().isEmpty() && diff.entriesOnlyOnRight().isEmpty()) { - for (Map.Entry entry : diff.entriesOnlyOnLeft().entrySet()) { - Type type = entry.getKey(); - Integer count = entry.getValue(); - if (count == 1) { - TypeWithContext inserted = clean.stream().filter(t -> t.type().equals(type)).findFirst().orElseThrow(); - int offset = rearrangeClean.indexOf(inserted); - if (offset == -1) { - throw new IllegalStateException("Missing inserted from clean list, bug?"); - } - tempDiff.remove(offset); - cleanGroup.remove(type); - rearrangeClean.remove(inserted); - } + // Sort by insertion order first + for (Pair p : sortMapDiff(diff.entriesOnlyOnLeft(), clean, true)) { + Type type = p.getFirst(); + TypeWithContext inserted = p.getSecond(); + + int offset = inserted.pos() - (int) builder.getRemovals().stream().filter(i -> i < inserted.pos()).count(); + tempDiff.remove(offset); + cleanGroup.remove(type); + rearrangeClean.remove(inserted); } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java index 381abc13..6dc84269 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java @@ -55,7 +55,7 @@ public boolean satisfiesIndexLimit(int index) { @Override public ParameterTransformer asParameterTransformer(Set flags) { - return new ReplaceParametersTransformer(this.index, this.type, flags.contains(Flags.UPGRADE_WRAP_OP)); + return new ReplaceParametersTransformer(this.index, this.type); } } @@ -106,7 +106,7 @@ public boolean satisfiesIndexLimit(int index) { @Override public ParameterTransformer asParameterTransformer(Set flags) { - return new RemoveParameterTransformer(this.index); + return new RemoveParameterTransformer(this.index, flags.contains(Flags.REMOVED_VAR_GRAVE)); } } @@ -209,9 +209,23 @@ public List removals() { .toList(); } + @Override + public LayeredParamsDiffSnapshot offset(int offset) { + return new LayeredParamsDiffSnapshot( + this.modifications.stream() + .map(p -> p.offset(offset)) + .toList() + ); + } + @Override public LayeredParamsDiffSnapshot offset(int offset, int limit) { - return new LayeredParamsDiffSnapshot(this.modifications.stream().filter(p -> p.satisfiesIndexLimit(limit)).map(p -> p.offset(offset)).toList()); + return new LayeredParamsDiffSnapshot( + this.modifications.stream() + .filter(p -> p.satisfiesIndexLimit(limit)) + .map(p -> p.offset(offset)) + .toList() + ); } @Override diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java index 95331c91..25234bd8 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java @@ -13,7 +13,7 @@ public interface ParamsDiffSnapshot { enum Flags { - UPGRADE_WRAP_OP + REMOVED_VAR_GRAVE } boolean isEmpty(); @@ -32,10 +32,12 @@ enum Flags { List>> inlines(); + ParamsDiffSnapshot offset(int offset); + ParamsDiffSnapshot offset(int offset, int limit); default MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset) { - return asParameterTransformer(type, withOffset, EnumSet.of(Flags.UPGRADE_WRAP_OP)); + return asParameterTransformer(type, withOffset, EnumSet.of(ParamsDiffSnapshot.Flags.REMOVED_VAR_GRAVE)); } MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset, Set flags); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java index 9093cd66..e9c795d4 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java @@ -28,13 +28,23 @@ public boolean matchesAny(Collection descs) { public AnnotationNode unwrap() { return this.annotationNode; } - + public AnnotationHandle copy() { AnnotationNode copy = new AnnotationNode(this.annotationNode.desc); this.annotationNode.accept(copy); return new AnnotationHandle(copy); } + public AnnotationHandle getNestedOrAppend(String key, String desc) { + AnnotationHandle existing = getNested(key).orElse(null); + if (existing != null) { + return existing; + } + AnnotationNode node = new AnnotationNode(desc); + appendValue(key, node); + return getNested(key).orElseThrow(); + } + public Optional getNested(String key) { return getValue(key) .flatMap(AnnotationValueHandle::maybeUnwrap) diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FrameUtil.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FrameUtil.java new file mode 100644 index 00000000..248d1985 --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FrameUtil.java @@ -0,0 +1,69 @@ +package org.sinytra.adapter.patch.analysis.selector; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.analysis.Analyzer; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.SourceInterpreter; +import org.objectweb.asm.tree.analysis.SourceValue; + +public class FrameUtil { + public static Frame[] getFrames(MethodNode methodNode) { + try { + Analyzer analyzer = new Analyzer<>(new SourceInterpreter()); + return analyzer.analyze(Object.class.getName(), methodNode); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // Helper to determine how many stack items an instruction consumes + public static int getPopCount(AbstractInsnNode insn) { + int op = insn.getOpcode(); + + // Method Calls + if (insn instanceof MethodInsnNode) { + // Static: pops args + // Virtual/Special/Interface: pops args + receiver (1) + int args = org.objectweb.asm.Type.getArgumentsAndReturnSizes(((MethodInsnNode) insn).desc) >> 2; + boolean isStatic = op == Opcodes.INVOKESTATIC; + // INVOKEDYNAMIC is complex, but usually acts like static for the bootstrap + if (op == org.objectweb.asm.Opcodes.INVOKEDYNAMIC) isStatic = true; + + return isStatic ? args : args + 1; + } + + // Field Instructions + if (insn instanceof FieldInsnNode) { + // PUTFIELD pops [ref, value] (value size depends on type) + // PUTSTATIC pops [value] + // GETFIELD pops [ref] -> Returns 1 + // GETSTATIC pops [] -> Returns 0 + if (op == Opcodes.GETSTATIC) return 0; + if (op == Opcodes.GETFIELD) return 1; + + // PUT logic requires checking field type size + boolean isLongOrDouble = ((FieldInsnNode) insn).desc.matches("[JD]"); + int valSize = isLongOrDouble ? 2 : 1; + if (op == Opcodes.PUTSTATIC) return valSize; + if (op == Opcodes.PUTFIELD) return valSize + 1; + } + + // Simple Opcodes (incomplete list, add others as needed) + return switch (op) { + case Opcodes.IADD, Opcodes.ISUB, Opcodes.IMUL, Opcodes.IDIV -> + // ... (most binary ops) + 2; + case Opcodes.INEG, Opcodes.I2L -> + // ... (unary ops) + 1; + case Opcodes.POP -> 1; + case Opcodes.POP2 -> 2; + case Opcodes.DUP -> 1; // Technically pops 1 to read it + default -> 0; + }; + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java b/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java index 07feb372..60799515 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java @@ -1,7 +1,6 @@ package org.sinytra.adapter.patch.api; import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionTarget; import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMethodAccess; import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMixinType; @@ -13,8 +12,6 @@ public interface MethodTransformBuilder> { T modifyTarget(String... methods); - T modifyTarget(ModifyInjectionTarget.Action action, String... methods); - T modifyMethodAccess(ModifyMethodAccess.AccessChange... changes); T extractMixin(String targetClass); @@ -36,8 +33,6 @@ default T modifyInjectionPoint(String value, String target) { T modifyInjectionPoint(String value, String target, boolean resetValues); - T modifyInjectionPoint(String value, String target, boolean resetValues, boolean dontUpgrade); - default T modifyInjectionPoint(String target) { return modifyInjectionPoint(null, target); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformFilter.java b/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformFilter.java deleted file mode 100644 index 66d10e32..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformFilter.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.sinytra.adapter.patch.api; - -public interface MethodTransformFilter { - boolean test(MethodContext methodContext); -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java b/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java index 51c28a54..745077e7 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java @@ -1,5 +1,6 @@ package org.sinytra.adapter.patch.api; +import org.objectweb.asm.Type; import org.spongepowered.asm.mixin.FabricUtil; import java.util.List; @@ -24,6 +25,7 @@ public class MixinConstants { public static final String WRAP_OPERATION_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/wrapoperation/WrapOperation"; public static final String WRAP_WITH_CONDITION = "Lcom/llamalad7/mixinextras/injector/WrapWithCondition;"; public static final String OPERATION_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/wrapoperation/Operation"; + public static final Type OPERATION_TYPE = Type.getObjectType(OPERATION_INTERNAL_NAME); public static final String LOCAL = "Lcom/llamalad7/mixinextras/sugar/Local;"; public static final String SHARE = "Lcom/llamalad7/mixinextras/sugar/Share;"; // Adapter custom mixin injectors @@ -39,4 +41,9 @@ public class MixinConstants { public static final List LVT_COMPATIBILITY_LEVELS = List.of(FabricUtil.COMPATIBILITY_0_10_0, FabricUtil.COMPATIBILITY_0_9_2); public static final String DEPRECATED = "Ljava/lang/Deprecated;"; + + // Types + public static final Type CI_TYPE = Type.getObjectType("org/spongepowered/asm/mixin/injection/callback/CallbackInfo"); + public static final Type CIR_TYPE = Type.getObjectType("org/spongepowered/asm/mixin/injection/callback/CallbackInfoReturnable"); + public static final Type OBJECT_TYPE = Type.getType(Object.class); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java index 24f570c8..2050d565 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.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.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.api.ClassTransform; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; @@ -64,9 +64,9 @@ public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle> results = MethodCallAnalyzer.analyzeMethod(method, (m, v) -> m.getOpcode() == Opcodes.INVOKEVIRTUAL, (insn, values) -> { + List> results = MethodAnalyzer.analyzeMethod(method, (m, v) -> m.getOpcode() == Opcodes.INVOKEVIRTUAL, (insn, values) -> { if (!values.isEmpty()) { - AbstractInsnNode valueInsn = MethodCallAnalyzer.getSingleInsn(values, 0); + AbstractInsnNode valueInsn = AdapterUtil.getSingleInsn(values, 0); if (valueInsn instanceof FieldInsnNode finsn) { return Pair.of(finsn, insn); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/MethodUpgrader.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/MethodUpgrader.java deleted file mode 100644 index 59958a01..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/MethodUpgrader.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.sinytra.adapter.patch.transformer; - -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -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.ParamsDiffSnapshot; -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.MethodTransform; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformTarget; -import org.sinytra.adapter.patch.transformer.operation.param.ParameterTransformer; -import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.Comparator; -import java.util.List; -import java.util.Set; - -public final class MethodUpgrader { - - public static void upgradeMethod(MethodNode methodNode, MethodContext methodContext, String originalDesc, String modifiedDesc) { - MethodQualifier cleanQualifier = MethodQualifier.create(originalDesc).orElse(null); - if (cleanQualifier == null) { - return; - } - MethodQualifier dirtyQualifier = MethodQualifier.create(modifiedDesc).orElse(null); - if (dirtyQualifier == null) { - return; - } - AnnotationHandle annotation = methodContext.methodAnnotation(); - if (annotation.matchesDesc(MixinConstants.MODIFY_ARGS)) { - ModifyArgsOffsetTransformer.handleModifiedDesc(methodNode, cleanQualifier.desc(), dirtyQualifier.desc()); - } else if (annotation.matchesDesc(MixinConstants.WRAP_OPERATION)) { - upgradeWrapOperation(methodNode, methodContext, cleanQualifier, dirtyQualifier); - } else if (annotation.matchesDesc(MixinConstants.MODIFY_EXPR_VAL)) { - upgradeModifyExpValue(methodNode, methodContext, cleanQualifier, dirtyQualifier); - } - } - - private static void upgradeModifyExpValue(MethodNode methodNode, MethodContext methodContext, MethodQualifier cleanQualifier, MethodQualifier dirtyQualifier) { - if (dirtyQualifier.desc() == null || cleanQualifier.desc() == null) { - return; - } - List originalTargetDesc = List.of(Type.getArgumentTypes(cleanQualifier.desc())); - List modifiedTargetDesc = List.of(Type.getArgumentTypes(dirtyQualifier.desc())); - List originalDesc = List.of(Type.getArgumentTypes(methodNode.desc)); - final List originalDescRef = originalDesc; - List> localAnnotations = AdapterUtil.getAnnotatedParameters(methodNode, originalDesc.toArray(Type[]::new), MixinConstants.LOCAL, Pair::of).stream() - .sorted(Comparator.comparingInt(i -> originalDescRef.indexOf(i.getSecond()))) - .toList(); - if (!localAnnotations.isEmpty()) { - originalDesc = originalDesc.subList(0, originalDesc.indexOf(localAnnotations.getFirst().getSecond())); - } - if (originalDesc.size() == 1) { - return; - } - - int capturedParams = Math.min(originalTargetDesc.size(), originalDesc.size() - 1); - int popParams = originalTargetDesc.size() - capturedParams; - List modifiedDesc = ImmutableList.builder() - // Add return object parameter - .add(originalDesc.getFirst()) - // Add target parameters - .addAll(modifiedTargetDesc.subList(0, modifiedTargetDesc.size() - popParams)) - .build(); - // Create diff - LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(originalDesc, modifiedDesc); - if (!diff.isEmpty()) { - MethodTransform patch = diff.asParameterTransformer(ParamTransformTarget.ALL, false, Set.of()); - patch.apply(methodContext); - } - } - - // TODO This should be an automatic upgrade tbh - public static void adjustInjectorOrdinalForNewMethod(MethodInsnNode minsn, MethodContext methodContext) { - AnnotationValueHandle handle = methodContext.injectionPointAnnotationOrThrow().getValue("ordinal").orElse(null); - if (handle == null) { - return; - } - int originalOrdinal = handle.get(); - // Temporarily adjust ordinal to account for previous calls that have not been moved to the new class - if (handle != null) { - handle.set(-1); - List insns = methodContext.computeInjectionTargetInsns(methodContext.findDirtyInjectionTarget()); - handle.set(originalOrdinal); - int newOrdinal = originalOrdinal; - for (AbstractInsnNode insn : methodContext.findDirtyInjectionTarget().methodNode().instructions) { - if (insn == minsn) { - break; - } - if (insns.contains(insn)) { - newOrdinal--; - } - } - if (newOrdinal >= 0) { - handle.set(newOrdinal); - } - } - } - - public static void upgradeCapturedLocals(MethodNode methodNode, MethodContext methodContext) { - AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(methodNode, methodContext); - if (capturedLocals == null) { - return; - } - - List availableLocals = methodContext.getTargetMethodLocals(capturedLocals.target()); - // For now, only handle cases where all locals are part of the method's params, convenient when switching the target to a lambda - if (availableLocals == null || !availableLocals.isEmpty()) { - return; - } - - LocalVarAnalyzer.CapturedLocalsTransform transform = LocalVarAnalyzer.analyzeCapturedLocals(capturedLocals, methodNode); - transform.remover().apply(methodContext); - - List expected = List.of(Type.getArgumentTypes(methodNode.desc)); - List required = ImmutableList.builder() - .add(Type.getArgumentTypes(capturedLocals.target().methodNode().desc)) - .add(AdapterUtil.getMixinCallableReturnType(capturedLocals.target().methodNode())) - .build(); - LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(expected, required); - if (!diff.isEmpty()) { - List transformers = diff.modifications().stream() - .map(paramModification -> paramModification.asParameterTransformer(Set.of())) - .toList(); - MethodTransform patch = TransformParameters.builder().transform(transformers).withOffset().targetType(ParamTransformTarget.METHOD).build(); - patch.apply(methodContext); - } - } - - private static void upgradeWrapOperation(MethodNode methodNode, MethodContext methodContext, MethodQualifier cleanQualifier, MethodQualifier dirtyQualifier) { - if (dirtyQualifier.owner() == null || cleanQualifier.desc() == null) { - return; - } - List originalTargetDesc = List.of(Type.getArgumentTypes(cleanQualifier.desc())); - List modifiedTargetDesc = List.of(Type.getArgumentTypes(dirtyQualifier.desc())); - List originalDesc = List.of(Type.getArgumentTypes(methodNode.desc)); - List modifiedDesc = ImmutableList.builder() - // Add instance parameter - .add(Type.getType(dirtyQualifier.owner())) - // Add target parameters - .addAll(modifiedTargetDesc) - // Add everything after the original owner and target args (such as captured locals) - .addAll(originalDesc.subList(1 + originalTargetDesc.size(), originalDesc.size())) - .build(); - // Create diff - LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(originalDesc, modifiedDesc); - if (!diff.isEmpty()) { - MethodTransform patch = diff.asParameterTransformer(ParamTransformTarget.ALL, false, Set.of(ParamsDiffSnapshot.Flags.UPGRADE_WRAP_OP)); - patch.apply(methodContext); - } - } - - public static void upgradeWrapOperationLayered(MethodContext methodContext, MethodQualifier cleanQualifier, MethodQualifier dirtyQualifier) { - if (dirtyQualifier.owner() == null || cleanQualifier.desc() == null) { - return; - } - List originalTargetDesc = List.of(Type.getArgumentTypes(cleanQualifier.desc())); - List modifiedTargetDesc = List.of(Type.getArgumentTypes(dirtyQualifier.desc())); - MethodNode methodNode = methodContext.getMixinMethod(); - List originalDesc = List.of(Type.getArgumentTypes(methodNode.desc)); - List modifiedDesc = ImmutableList.builder() - // Add instance parameter - .add(Type.getType(dirtyQualifier.owner())) - // Add target parameters - .addAll(modifiedTargetDesc) - // Add everything after the original owner and target args (such as captured locals) - .addAll(originalDesc.subList(1 + originalTargetDesc.size(), originalDesc.size())) - .build(); - // Create diff - LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(originalDesc, modifiedDesc); - if (!diff.isEmpty()) { - MethodTransform patch = diff.asParameterTransformer(ParamTransformTarget.ALL, false, Set.of()); - patch.apply(methodContext); - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetTransformer.java deleted file mode 100644 index 927e4644..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetTransformer.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.sinytra.adapter.patch.transformer; - -import com.mojang.datafixers.util.Pair; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.IntInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.List; - -@Deprecated // TODO Remove in favor of Processors -public class ModifyArgsOffsetTransformer { - private static final MethodQualifier ARGS_GET = new MethodQualifier("Lorg/spongepowered/asm/mixin/injection/invoke/arg/Args;", "get", "(I)Ljava/lang/Object;"); - private static final MethodQualifier ARGS_SET = new MethodQualifier("Lorg/spongepowered/asm/mixin/injection/invoke/arg/Args;", "set", "(ILjava/lang/Object;)V"); - - public static void handleModifiedDesc(MethodNode methodNode, String cleanDesc, String dirtyDesc) { - List cleanArgs = MethodParameters.getParameterTypes(cleanDesc); - List dirtyArgs = MethodParameters.getParameterTypes(dirtyDesc); - LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(cleanArgs, dirtyArgs); - if (!diff.insertions().isEmpty()) { - modify(methodNode, diff.insertions()); - } - } - - public static void modify(MethodNode methodNode, List> insertions) { - List insns = MethodCallAnalyzer.analyzeMethod(methodNode, (insn, values) -> (ARGS_GET.matches(insn) || ARGS_SET.matches(insn)) && values.size() > 1, (insn, values) -> MethodCallAnalyzer.getSingleInsn(values, 1)); - for (AbstractInsnNode insn : insns) { - if (insn instanceof IntInsnNode iinsn) { - insertions.forEach(pair -> { - int index = pair.getFirst(); - if (index >= iinsn.operand) { - iinsn.operand += 1; - } - }); - } - else if (insn instanceof InsnNode iinsn) { - int index = AdapterUtil.getInsnIntConstValue(iinsn); - int newIndex = index + (int) insertions.stream().filter(p -> p.getFirst() >= index).count(); - methodNode.instructions.set(insn, AdapterUtil.getIntConstInsn(newIndex)); - } - else { - throw new UnsupportedOperationException("Whoopsie! We can't handle " + insn.getClass().getName() + " instructions just yet!"); - } - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetUpgrader.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetUpgrader.java new file mode 100644 index 00000000..9fa78359 --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetUpgrader.java @@ -0,0 +1,37 @@ +package org.sinytra.adapter.patch.transformer; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.MethodQualifier; + +import java.util.List; + +public class ModifyArgsOffsetUpgrader { + private static final MethodQualifier ARGS_GET = new MethodQualifier("Lorg/spongepowered/asm/mixin/injection/invoke/arg/Args;", "get", "(I)Ljava/lang/Object;"); + private static final MethodQualifier ARGS_SET = new MethodQualifier("Lorg/spongepowered/asm/mixin/injection/invoke/arg/Args;", "set", "(ILjava/lang/Object;)V"); + + public static void upgradeAfterParamInsert(MethodNode methodNode, int index) { + List insns = MethodAnalyzer.analyzeMethod(methodNode, + (insn, values) -> (ARGS_GET.matches(insn) || ARGS_SET.matches(insn)) && values.size() > 1, + (insn, values) -> AdapterUtil.getSingleInsn(values, 1) + ); + for (AbstractInsnNode insn : insns) { + if (insn instanceof IntInsnNode iinsn) { + if (index >= iinsn.operand) { + iinsn.operand += 1; + } + } else if (insn instanceof InsnNode iinsn) { + int insnIndex = AdapterUtil.getInsnIntConstValue(iinsn); + if (index >= insnIndex) { + methodNode.instructions.set(insn, AdapterUtil.getIntConstInsn(insnIndex + 1)); + } + } else { + throw new UnsupportedOperationException("Whoopsie! We can't handle " + insn.getClass().getName() + " instructions just yet!"); + } + } + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java index 1a41e673..4f2ece2a 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java @@ -2,7 +2,6 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.*; @@ -42,7 +41,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont if (insn instanceof MethodInsnNode minsn && minsn.name.equals(q.name()) && minsn.desc.equals(q.desc()) && !minsn.owner.equals(owner) && (context.environment().inheritanceHandler().isClassInherited(minsn.owner, owner) || isFixedField(minsn, context)) ) { - target.set(MethodCallAnalyzer.getCallQualifier(minsn)); + target.set(MethodQualifier.create(minsn).asDescriptor()); if (methodContext.methodAnnotation().matchesDesc(MixinConstants.REDIRECT) && minsn.getOpcode() != Opcodes.INVOKESTATIC) { methodNode.visitParameterAnnotation(0, MixinConstants.COERCE, false); } 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 2f82d971..d3649bc3 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 @@ -9,6 +9,8 @@ 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.method.MethodAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.*; @@ -128,8 +130,8 @@ public Optional apply(MethodContext methodContext, ClassNode classNode, String target = context.target(); int ordinal = context.ordinal(); - Multimap cleanCallsMap = MethodCallAnalyzer.getMethodCalls(cleanTarget.methodNode(), new ArrayList<>()); - Multimap dirtyCallsMap = MethodCallAnalyzer.getMethodCalls(dirtyTarget.methodNode(), new ArrayList<>()); + Multimap cleanCallsMap = MethodAnalyzer.getMethodCalls(cleanTarget.methodNode(), new ArrayList<>()); + Multimap dirtyCallsMap = MethodAnalyzer.getMethodCalls(dirtyTarget.methodNode(), new ArrayList<>()); PatchContext patchContext = methodContext.patchContext(); String cleanValue = patchContext.remap(target); @@ -139,8 +141,8 @@ public Optional apply(MethodContext methodContext, ClassNode classNode, if (cleanCalls.size() != dirtyCalls.size()) { int insnRange = 5; - List cleanMatchers = cleanCalls.stream().map(i -> MethodCallAnalyzer.findSurroundingInstructions(i, insnRange)).toList(); - List dirtyMatchers = dirtyCalls.stream().map(i -> MethodCallAnalyzer.findSurroundingInstructions(i, insnRange)).toList(); + List cleanMatchers = cleanCalls.stream().map(i -> MethodInsnMatcher.findSurroundingInstructions(i, insnRange)).toList(); + List dirtyMatchers = dirtyCalls.stream().map(i -> MethodInsnMatcher.findSurroundingInstructions(i, insnRange)).toList(); if (ordinal >= 0 && ordinal < cleanMatchers.size()) { InstructionMatcher original = cleanMatchers.get(ordinal); 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 0f570590..82197440 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 @@ -194,7 +194,6 @@ private static int getMaxLocalIndex(List expected, List parameterTypes, List newParameterTypes) { diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java index 57131488..346769a0 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java @@ -3,11 +3,12 @@ import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; 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.transformer.operation.unit.ModifyMixinType; +import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.MockMixinRuntime; import org.spongepowered.asm.mixin.injection.modify.LocalVariableDiscriminator; import org.spongepowered.asm.mixin.injection.struct.InjectionInfo; @@ -103,7 +104,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont return Patch.Result.PASS; } // Get method call argument instructions - List args = MethodCallAnalyzer.findMethodCallParamInsns(dirtyTarget.methodNode(), dirtyMinsn); + List args = MethodCallAnalyzer.getMethodCallSrcInsns(dirtyTarget.methodNode(), dirtyMinsn); if (args == null) { return Patch.Result.PASS; } @@ -116,7 +117,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont // Cannot apply twice return Patch.Result.PASS; } - String qualifier = MethodCallAnalyzer.getCallQualifier(dirtyMinsn); + String qualifier = MethodQualifier.create(dirtyMinsn).asDescriptor(); final int index = i; methodContext.recordAudit(this, "Redirect RETURN variable modifier to parameter %s of method call to %s", i, qualifier); MethodTransform transform = new ModifyMixinType(MixinConstants.MODIFY_ARG, b -> b.sameTarget() 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/dynamic/LocalCaptureUpgradePreprocessor.java similarity index 69% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixLocalCaptureUpgrade.java rename to definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/LocalCaptureUpgradePreprocessor.java index 9cfe30d9..30b9d743 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixLocalCaptureUpgrade.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/LocalCaptureUpgradePreprocessor.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.dynfix; +package org.sinytra.adapter.patch.transformer.dynamic; import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.Nullable; @@ -8,21 +8,35 @@ 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.api.*; 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) {} - +public class LocalCaptureUpgradePreprocessor implements MethodTransform { @Override + public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { + if (methodContext.findCleanInjectionTarget() == null) { + return Patch.Result.PASS; + } + + Data data = prepare(methodContext); + if (data != null) { + PatchAuditTrail auditTrail = context.environment().auditTrail(); + Patch.Result result = apply(methodNode, methodContext, auditTrail, data); + auditTrail.recordResult(methodContext, PatchAuditTrail.Match.FULL); + return result; + } + + return Patch.Result.PASS; + } + + public record Data(AdapterUtil.CapturedLocals capturedLocals, LocalVarAnalyzer.CapturedLocalsTransform transform) { + } + @Nullable - public DynFixLocalCaptureUpgrade.Data prepare(MethodContext methodContext) { + public LocalCaptureUpgradePreprocessor.Data prepare(MethodContext methodContext) { if (methodContext.findDirtyInjectionTarget() == null) { return null; } @@ -55,14 +69,13 @@ public DynFixLocalCaptureUpgrade.Data prepare(MethodContext methodContext) { return new Data(info.capturedLocals(), transform); } - @Override @Nullable - public FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchAuditTrail auditTrail, Data data) { + public Patch.Result apply(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); @@ -72,6 +85,6 @@ public FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext auditTrail.recordAudit(this, methodContext, "Upgrade captured locals"); - return FixResult.of(result, PatchAuditTrail.Match.FULL); + return result; } } 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 deleted file mode 100644 index 61be4980..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynFixMethodComparison.java +++ /dev/null @@ -1,359 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynfix; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.InsnComparator; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; -import org.sinytra.adapter.patch.analysis.MethodLabelComparator; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -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.transformer.MethodUpgrader; -import org.sinytra.adapter.patch.transformer.operation.CompoundMethodTransform; -import org.sinytra.adapter.patch.transformer.operation.param.*; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionPoint; -import org.sinytra.adapter.patch.util.AdapterUtil; - -import java.util.*; -import java.util.stream.Stream; - -public class DynFixMethodComparison implements DynamicFixer { - private static final Set ACCEPTED_ANNOTATIONS = Set.of(MixinConstants.INJECT, MixinConstants.WRAP_OPERATION, MixinConstants.MODIFY_ARG); - - public record Data(AbstractInsnNode cleanInjectionInsn) {} - - @Nullable - @Override - public Data prepare(MethodContext methodContext) { - if (methodContext.methodAnnotation().matchesAny(ACCEPTED_ANNOTATIONS) && methodContext.findDirtyInjectionTarget() != null) { - MethodContext.TargetPair cleanInjectionTarget = methodContext.findCleanInjectionTarget(); - if (cleanInjectionTarget == null) { - return null; - } - List cleanInsns = methodContext.findInjectionTargetInsns(cleanInjectionTarget); - if (!cleanInsns.isEmpty()) { - return new Data(cleanInsns.getFirst()); - } - } - return null; - } - - @Override - @Nullable - public FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchAuditTrail auditTrail, Data data) { - AbstractInsnNode cleanInjectionInsn = data.cleanInjectionInsn(); - MethodLabelComparator.ComparisonResult comparisonResult = MethodLabelComparator.findPatchedLabels(cleanInjectionInsn, methodContext); - if (comparisonResult == null) { - return null; - } - List> hunkLabels = comparisonResult.patchedLabels(); - - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.MODIFY_ARG)) { - return handleModifyArgInjectionPoint(cleanInjectionInsn, hunkLabels, methodContext); - } - - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { - return handleWrapOperationToInstanceOf(cleanInjectionInsn, comparisonResult.cleanLabel(), hunkLabels, methodContext) - .or(() -> handleWrapOperationAdaptedTarget(cleanInjectionInsn, hunkLabels, methodContext)) - .or(() -> handleWrapOperationNewInjectionPoint(cleanInjectionInsn, comparisonResult.cleanLabel(), hunkLabels, methodContext)) - .or(() -> handleTargetModification(hunkLabels, methodContext)) - .orElse(null); - } - - ClassNode cleanTargetClass = methodContext.findCleanInjectionTarget().classNode(); - for (List insns : hunkLabels) { - for (AbstractInsnNode insn : insns) { - if (insn instanceof MethodInsnNode minsn && minsn.getOpcode() == Opcodes.INVOKESTATIC && !minsn.owner.equals(cleanTargetClass.name)) { - Patch.Result result = attemptExtractMixin(minsn, methodContext); - if (result != Patch.Result.PASS) { - return FixResult.of(result, PatchAuditTrail.Match.FULL); - } - } - } - } - - // If extraction fails, fall back to injecting at the nearest method call in dirty code - for (List insns : hunkLabels) { - for (AbstractInsnNode insn : insns) { - if (insn instanceof MethodInsnNode minsn) { - String newInjectionPoint = Type.getObjectType(minsn.owner).getDescriptor() + minsn.name + minsn.desc; - return FixResult.of(new ModifyInjectionPoint("INVOKE", newInjectionPoint, true, false).apply(methodContext), PatchAuditTrail.Match.PARTIAL); - } - } - } - - return null; - } - - // Handle ModifyArg when targetting INDY values - private static FixResult handleModifyArgInjectionPoint(AbstractInsnNode cleanInjectionInsn, List> hunkLabels, MethodContext methodContext) { - if (!(cleanInjectionInsn instanceof MethodInsnNode minsn)) { - return null; - } - - Type desiredType = Type.getArgumentTypes(methodContext.getMixinMethod().desc)[0]; - - int index = MethodCallAnalyzer.getArgIndex(minsn.desc, desiredType) + 1; - if (index == 0) { - return null; - } - List cleanCallParamInsns = MethodCallAnalyzer.findMethodCallParamInsns(methodContext.findCleanInjectionTarget().methodNode(), minsn); - if (cleanCallParamInsns.size() <= index) { - return null; - } - - AbstractInsnNode targetArgInsn = cleanCallParamInsns.get(index); - if (!(targetArgInsn instanceof InvokeDynamicInsnNode cleanIndy)) { - return null; - } - - MethodContext.TargetPair cleanTarget = methodContext.findCleanInjectionTarget(); - MethodContext.TargetPair dirtyTarget = methodContext.findDirtyInjectionTarget(); - // Handle cases where the method has been split off - if (cleanIndy.bsmArgs.length > 2 && cleanIndy.bsmArgs[1] instanceof Handle handle && handle.getOwner().equals(dirtyTarget.classNode().name)) { - MethodNode cleanMethod = MethodCallAnalyzer.findMethodByUniqueName(cleanTarget.classNode(), handle.getName()).orElse(null); - if (cleanMethod == null) { - return null; - } - MethodNode dirtyMethod = MethodCallAnalyzer.findMethodByUniqueName(dirtyTarget.classNode(), handle.getName()).orElse(null); - if (dirtyMethod == null) { - return null; - } - if (MethodCallAnalyzer.isDirtyDeprecatedMethod(cleanMethod, dirtyMethod)) { - List invocations = MethodCallAnalyzer.collectMethodInvocations(dirtyTarget.classNode(), dirtyMethod); - if (invocations != null) { - MethodNode last = invocations.getLast(); - if (last.desc.equals(dirtyMethod.desc)) { - InvokeDynamicInsnNode clone = (InvokeDynamicInsnNode) cleanIndy.clone(Map.of()); - clone.bsmArgs = Stream.of(clone.bsmArgs).toArray(); - clone.bsmArgs[1] = new Handle(handle.getTag(), handle.getOwner(), last.name, handle.getDesc(), handle.isInterface()); - cleanIndy = clone; - } - } - } - } - - MethodNode dirtyMethod = methodContext.findDirtyInjectionTarget().methodNode(); - List matches = new ArrayList<>(); - for (List label : hunkLabels) { - for (AbstractInsnNode insn : label) { - if (insn instanceof MethodInsnNode m && Stream.of(Type.getArgumentTypes(m.desc)).filter(desiredType::equals).count() == 1) { - int argIndex = MethodCallAnalyzer.getArgIndex(m.desc, desiredType) + 1; - if (argIndex == 0) { - continue; - } - List list = MethodCallAnalyzer.findMethodCallParamInsns(dirtyMethod, m); - if (list.size() > argIndex && list.get(argIndex) instanceof InvokeDynamicInsnNode dirtyIndy && InsnComparator.insnEqual(cleanIndy, dirtyIndy)) { - matches.add(m); - } - } - } - } - - if (matches.size() == 1) { - MethodInsnNode m = matches.getFirst(); - String newInjectionPoint = Type.getObjectType(m.owner).getDescriptor() + m.name + m.desc; - - Patch.Result result = CompoundMethodTransform.builder(new ModifyInjectionPoint("INVOKE", newInjectionPoint, true, false)) - .onSuccess(() -> (cls, mtd, mtx, ctx) -> { - int ordinal = MethodCallAnalyzer.getMethodCallOrdinal(dirtyMethod, m); - if (ordinal == -1) { - throw new IllegalStateException("Ordinal not found?"); - } - AnnotationHandle handle = mtx.injectionPointAnnotationOrThrow(); - handle.setOrAppendNonNull("ordinal", ordinal); - return Patch.Result.APPLY; - }) - .apply(methodContext); - - return FixResult.of(result, PatchAuditTrail.Match.FULL); - } - - return null; - } - - private static Optional handleWrapOperationAdaptedTarget(AbstractInsnNode cleanInjectionInsn, List> hunkLabels, MethodContext methodContext) { - if (!(cleanInjectionInsn instanceof MethodInsnNode minsn) || hunkLabels.size() != 1) { - return Optional.empty(); - } - - List methodCalls = hunkLabels.getFirst().stream() - .filter(i -> i instanceof MethodInsnNode) - .map(i -> (MethodInsnNode) i) - .toList(); - if (methodCalls.size() != 1) { - return Optional.empty(); - } - - Patch.Result result = WrapOperationSurgeon.tryUpgrade(methodContext, minsn, methodCalls.getLast()); - - return Optional.ofNullable(FixResult.of(result, PatchAuditTrail.Match.FULL)); - } - - private static Optional handleWrapOperationNewInjectionPoint(AbstractInsnNode cleanInjectionInsn, List cleanLabel, List> hunkLabels, MethodContext methodContext) { - if (!(cleanInjectionInsn instanceof MethodInsnNode minsn) || hunkLabels.size() != 1) { - return Optional.empty(); - } - Type cleanReturnType = Type.getReturnType(minsn.desc); - List dirtyLabel = hunkLabels.getFirst(); - List cleanMethodCalls = cleanLabel.stream().filter(i -> i instanceof MethodInsnNode m && m.owner.equals(minsn.owner) && Type.getReturnType(m.desc).equals(cleanReturnType)).map(i -> ((MethodInsnNode) i).name).toList(); - List methodCalls = dirtyLabel.stream() - .filter(i -> i instanceof MethodInsnNode m && m.owner.equals(minsn.owner) && Type.getReturnType(m.desc).equals(cleanReturnType) && !cleanMethodCalls.contains(m.name)) - .map(i -> (MethodInsnNode) i) - .toList(); - if (methodCalls.size() != 1) { - return Optional.empty(); - } - MethodInsnNode dirtyMinsn = methodCalls.getFirst(); - Patch.Result result = CompoundMethodTransform.builder(b -> b - .modifyInjectionPoint("INVOKE", MethodCallAnalyzer.getCallQualifier(dirtyMinsn))) - .apply(methodContext); - return Optional.of(FixResult.of(result, PatchAuditTrail.Match.FULL)); - } - - private static Optional handleWrapOperationToInstanceOf(AbstractInsnNode cleanInjectionInsn, List cleanLabel, List> hunkLabels, MethodContext methodContext) { - if (!(cleanInjectionInsn instanceof MethodInsnNode minsn) || hunkLabels.size() != 1 || !(cleanLabel.getLast() instanceof JumpInsnNode) || cleanLabel.stream().anyMatch(i -> i instanceof TypeInsnNode)) { - return Optional.empty(); - } - List dirtyLabel = hunkLabels.getFirst(); - if (!(dirtyLabel.getLast() instanceof JumpInsnNode)) { - return Optional.empty(); - } - List instanceOfCalls = dirtyLabel.stream().filter(i -> i instanceof TypeInsnNode).map(i -> (TypeInsnNode) i).toList(); - if (instanceOfCalls.size() != 1) { - return Optional.empty(); - } - TypeInsnNode instanceOfCall = instanceOfCalls.getFirst(); - MethodNode methodNode = methodContext.getMixinMethod(); - LocalVariableLookup mixinLocals = new LocalVariableLookup(methodNode); - - Type[] argsTypes = Type.getArgumentTypes(methodNode.desc); - Set paramVars = new HashSet<>(); - for (int i = 0; i < argsTypes.length; i++) { - if (argsTypes[i].equals(AdapterUtil.OPERATION_TYPE)) { - break; - } - LocalVariableNode lvn = mixinLocals.getByParameterOrdinal(i); - paramVars.add(lvn.index); - } - - ParamTransformationUtil.extractWrapOperation(methodContext, methodNode, List.of(argsTypes), op -> { - for (int i = 1; i < paramVars.size(); i++) { - op.removeParameter(i); - } - }); - - List originalOpCall = ParamTransformationUtil.findWrapOperationOriginalCallArgs(methodNode, methodContext); - Multimap usedVars = HashMultimap.create(); - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof VarInsnNode varInsn && !originalOpCall.contains(insn) && paramVars.contains(varInsn.var)) { - usedVars.put(varInsn.var, varInsn); - } - } - - List originalCallArgs = MethodCallAnalyzer.findMethodCallParamInsns(methodContext.findCleanInjectionTarget().methodNode(), minsn); - LocalVariableNode instanceLocal = mixinLocals.getByParameterOrdinal(0); - for (int paramVar : usedVars.keySet()) { - if (paramVar == instanceLocal.index) { - int cleanOrdinal = methodContext.cleanLocalsTable().getTypedOrdinal(methodContext.cleanLocalsTable().getByIndex(((VarInsnNode) originalCallArgs.getFirst()).var)).orElse(-1); - if (cleanOrdinal == -1) { - return Optional.empty(); - } - LocalVariableNode dirtyLocal = methodContext.dirtyLocalsTable().getByTypedOrdinal(Type.getType(instanceLocal.desc), cleanOrdinal).orElse(null); - if (dirtyLocal == null) { - return Optional.empty(); - } - TransformParameters.builder() - .transform(new InjectParameterTransform(argsTypes.length, Type.getType(dirtyLocal.desc), false)) - .build() - .apply(methodContext); - int newOrdinal = Type.getArgumentTypes(methodNode.desc).length - 1; - AnnotationVisitor visitor = methodNode.visitParameterAnnotation(newOrdinal, MixinConstants.LOCAL, false); - visitor.visit("ordinal", cleanOrdinal); - visitor.visitEnd(); - int newIndex = new LocalVariableLookup(methodNode).getByParameterOrdinal(newOrdinal).index; - usedVars.get(paramVar).forEach(varInsn -> varInsn.var = newIndex); - } else { - String loadedType = instanceOfCall.getPrevious() instanceof MethodInsnNode m ? Type.getReturnType(m.desc).getDescriptor() : null; - LocalVariableNode node = mixinLocals.getByIndex(paramVar); - if (loadedType == null || !loadedType.equals(node.desc)) { - return Optional.empty(); - } - usedVars.get(paramVar).forEach(varInsn -> varInsn.var = instanceLocal.index); - } - } - - Patch.Result result = TransformParameters.builder() - .transform(new ReplaceParametersTransformer(0, Type.getObjectType("java/lang/Object"), false)) - .chain(b -> { - for (int i = 1; i < paramVars.size(); i++) { - b.transform(new RemoveParameterTransformer(i, false)); - } - }) - .build() - .apply(methodContext); - if (result == Patch.Result.PASS) { - return Optional.empty(); - } - - AnnotationHandle ann = methodContext.methodAnnotation(); - ann.removeValues("at"); - AnnotationVisitor visitor = ann.unwrap().visitAnnotation("constant", MixinConstants.CONSTANT); - visitor.visit("classValue", Type.getObjectType(instanceOfCall.desc)); - visitor.visitEnd(); - - return Optional.of(FixResult.of(Patch.Result.APPLY, PatchAuditTrail.Match.FULL)); - } - - private static Optional handleTargetModification(List> hunkLabels, MethodContext methodContext) { - ClassNode dirtyTarget = methodContext.findDirtyInjectionTarget().classNode(); - for (List insns : hunkLabels) { - for (AbstractInsnNode insn : insns) { - if (insn instanceof MethodInsnNode minsn && minsn.owner.equals(dirtyTarget.name)) { - MethodNode method = MethodCallAnalyzer.findMethodByUniqueName(dirtyTarget, minsn.name).orElse(null); - if (method != null && !methodContext.findInjectionTargetInsns(new MethodContext.TargetPair(dirtyTarget, method)).isEmpty()) { - Patch.Result result = CompoundMethodTransform.builder(b -> b.modifyTarget(minsn.name + minsn.desc)) - .apply(methodContext); - return Optional.of(FixResult.of(result, PatchAuditTrail.Match.FULL)); - } - } - } - } - return Optional.empty(); - } - - private static Patch.Result attemptExtractMixin(MethodInsnNode minsn, MethodContext methodContext) { - // Looks like some code was moved into a static method outside this class - // Attempt extracting mixin - ClassNode targetClass = methodContext.patchContext().environment().dirtyClassLookup().getClass(minsn.owner).orElse(null); - if (targetClass == null) { - return Patch.Result.PASS; - } - - MethodNode targetMethod = methodContext.patchContext().environment().dirtyClassLookup().findMethod(minsn.owner, minsn.name, minsn.desc).orElse(null); - if (targetMethod == null) { - return Patch.Result.PASS; - } - - MethodUpgrader.adjustInjectorOrdinalForNewMethod(minsn, methodContext); - List newTargetInsns = methodContext.findInjectionTargetInsns(new MethodContext.TargetPair(targetClass, targetMethod)); - if (newTargetInsns.isEmpty()) { - return Patch.Result.PASS; - } - - return CompoundMethodTransform.builder(b -> b.extractMixin(minsn.owner)) - .onSuccess(b -> b.modifyTarget(minsn.name + minsn.desc)) - // Extraction failed? Let's try something else - .onFail(() -> new MirrorableExtractMixin(targetClass.name, minsn)) - .apply(methodContext); - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicFixer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicFixer.java deleted file mode 100644 index d03ea41a..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicFixer.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynfix; - -import org.jetbrains.annotations.Nullable; -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.Patch; -import org.sinytra.adapter.patch.api.PatchAuditTrail; - -public interface DynamicFixer { - @Nullable - DATA prepare(MethodContext methodContext); - - @Nullable - FixResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchAuditTrail auditTrail, DATA data); - - record FixResult(Patch.Result result, PatchAuditTrail.Match match) { - public FixResult { - if (result == Patch.Result.PASS) { - throw new IllegalArgumentException("Result must be non-PASS"); - } - } - - @Nullable - public static FixResult of(Patch.Result result, PatchAuditTrail.Match match) { - return result == Patch.Result.PASS ? null : new FixResult(result, match); - } - } - - final class EmptyData { - public static final EmptyData INSTANCE = new EmptyData(); - } -} 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 deleted file mode 100644 index 57bd225a..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/DynamicInjectionPointPatch.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynfix; - -import com.mojang.logging.LogUtils; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.api.*; -import org.slf4j.Logger; - -import java.util.List; - -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; - -@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> FIXES = List.of( - new DynFixMethodComparison() - ); - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - 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) { - 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); - - auditTrail.recordResult(methodContext, PatchAuditTrail.Match.NONE); - - for (DynamicFixer fix : FIXES) { - Object data = fix.prepare(methodContext); - if (data != null) { - DynamicFixer.FixResult fixResult = fix.apply(classNode, methodNode, methodContext, auditTrail, data); - if (fixResult != null) { - auditTrail.recordResult(methodContext, fixResult.match()); - return result.or(fixResult.result()); - } - } - } - } - - return result; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/WrapOperationSurgeon.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/WrapOperationSurgeon.java deleted file mode 100644 index 81c3fcef..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/WrapOperationSurgeon.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynfix; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.mojang.datafixers.util.Pair; -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; -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.fixes.BytecodeFixerUpper; -import org.sinytra.adapter.patch.transformer.MethodUpgrader; -import org.sinytra.adapter.patch.fixes.TypeAdapter; -import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil; -import org.sinytra.adapter.patch.transformer.operation.CompoundMethodTransform; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.OpcodeUtil; - -import java.util.*; -import java.util.function.Consumer; - -public class WrapOperationSurgeon { - - public static Patch.Result tryUpgrade(MethodContext methodContext, MethodInsnNode cleanInsn, MethodInsnNode dirtyInsn) { - MethodNode methodNode = methodContext.getMixinMethod(); - LocalVariableLookup mixinLocals = new LocalVariableLookup(methodNode); - - Multimap usedVars = getUsedVars(mixinLocals, methodContext); - Map>> adapters = new HashMap<>(); - - for (Integer key : usedVars.keys()) { - if (key == 0) { - Pair> pair = findReplacementForInstance(cleanInsn, dirtyInsn, methodContext); - if (pair != null) { - adapters.put(key, pair); - continue; - } - } - return Patch.Result.PASS; - } - - MethodQualifier oldQualifier = methodContext.getInjectionPointMethodQualifier(); - String newQualifier = MethodCallAnalyzer.getCallQualifier(dirtyInsn); - return CompoundMethodTransform.builder(b -> b.modifyInjectionPoint("INVOKE", newQualifier, false, true)) - .onSuccess(() -> (c, m, mtx, ctx) -> { - MethodUpgrader.upgradeWrapOperationLayered(methodContext, oldQualifier, MethodQualifier.create(newQualifier).orElseThrow()); - - usedVars.forEach((i, insn) -> { - Pair> adapter = adapters.get(i); - adapter.getFirst().apply(methodNode.instructions, insn); - }); - - for (Pair> pair : adapters.values()) { - if (pair.getSecond() != null) { - pair.getSecond().accept(methodNode.instructions); - } - } - - return Patch.Result.APPLY; - }) - .apply(methodContext); - } - - @Nullable - private static Pair> findReplacementForInstance(MethodInsnNode cleanInsn, MethodInsnNode dirtyInsn, MethodContext methodContext) { - MethodNode cleanTargetMethod = methodContext.findCleanInjectionTarget().methodNode(); - List receiverInsns = getMethodInvocationsInsns(cleanTargetMethod, cleanInsn, 0); - if (!receiverInsns.isEmpty() && receiverInsns.getFirst() instanceof VarInsnNode varInsn) { - BytecodeFixerUpper bfu = methodContext.patchContext().environment().bytecodeFixerUpper(); - if (bfu == null) { - return null; - } - - LocalVariableLookup cleanLookup = methodContext.cleanLocalsTable(); - LocalVariableNode lvn = cleanLookup.getByIndex(varInsn.var); - - TypeAdapter typeAdapter = bfu.getTypeAdapter(Type.getObjectType(dirtyInsn.owner), Type.getType(lvn.desc)); - if (typeAdapter == null) { - return null; - } - - List subList = receiverInsns.subList(1, receiverInsns.size()); - - TypeAdapter adapter = typeAdapter.andThen((list, insn) -> { - list.insert(insn, AdapterUtil.insnList(AdapterUtil.cloneInsns(subList))); - }); - Consumer castCheck = subList.getFirst() instanceof TypeInsnNode typeInsn && typeInsn.getOpcode() == Opcodes.CHECKCAST ? - list -> { - List originalWOCall = new ArrayList<>(ParamTransformationUtil.findWrapOperationOriginalCallArgs(methodContext.getMixinMethod(), methodContext)); - // Include final method call and cast - originalWOCall.add(originalWOCall.getLast().getNext()); - originalWOCall.add(originalWOCall.getLast().getNext()); - originalWOCall.add(originalWOCall.getLast().getNext()); - List cloned = AdapterUtil.cloneInsns(originalWOCall); - - boolean hasLabel = list.getFirst() instanceof LabelNode; - LabelNode label = hasLabel ? (LabelNode) list.getFirst() : new LabelNode(); - InsnList check = AdapterUtil.insnList( - new LabelNode(), - new VarInsnNode(Opcodes.ALOAD, 0), - new TypeInsnNode(Opcodes.INSTANCEOF, typeInsn.desc), - new JumpInsnNode(Opcodes.IFNE, label), - new LabelNode() - ); - typeAdapter.apply(check, check.get(1)); - check.add(AdapterUtil.insnList(cloned)); - check.add(new InsnNode(OpcodeUtil.getReturnOpcode(methodContext.getMixinMethod()))); - if (!hasLabel) { - check.add(label); - } - - list.insert(check); - } - : null; - - return Pair.of(adapter, castCheck); - } - return null; - } - - @Nullable - private static List getMethodInvocationsInsns(MethodNode method, MethodInsnNode minsn, int param) { - List insns = new ArrayList<>(); - if (getMethodInvocationsInsns(method, minsn, param, insns)) { - return insns; - } - return null; - } - - @Nullable - private static boolean getMethodInvocationsInsns(MethodNode method, MethodInsnNode minsn, int param, List insns) { - List invocationInsns = MethodCallAnalyzer.findMethodCallParamInsns(method, minsn); - if (invocationInsns.isEmpty()) { - return false; - } - AbstractInsnNode receiver = invocationInsns.getFirst(); - if (receiver instanceof VarInsnNode) { - insns.addAll(0, invocationInsns); - return true; - } else if (receiver instanceof TypeInsnNode typeInsn && receiver.getPrevious() instanceof VarInsnNode varInsn) { - insns.addFirst(typeInsn); - insns.addFirst(varInsn); - return true; - } else if (receiver instanceof MethodInsnNode invocation) { - List methodInsns = new ArrayList<>(); - if (getMethodInvocationsInsns(method, invocation, param, methodInsns)) { - insns.add(invocationInsns.get(param)); - insns.addAll(0, methodInsns); - return true; - } - } - return false; - } - - private static Multimap getUsedVars(LocalVariableLookup mixinLocals, MethodContext methodContext) { - MethodNode methodNode = methodContext.getMixinMethod(); - Type[] argsTypes = Type.getArgumentTypes(methodNode.desc); - Set paramVars = new HashSet<>(); - for (int i = 0; i < argsTypes.length; i++) { - if (argsTypes[i].equals(AdapterUtil.OPERATION_TYPE)) { - break; - } - LocalVariableNode lvn = mixinLocals.getByParameterOrdinal(i); - paramVars.add(lvn.index); - } - - List originalOpCall = ParamTransformationUtil.findWrapOperationOriginalCallArgs(methodNode, methodContext); - Multimap usedVars = HashMultimap.create(); - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof VarInsnNode varInsn && !originalOpCall.contains(insn) && paramVars.contains(varInsn.var)) { - usedVars.put(varInsn.var, varInsn); - } - } - - return usedVars; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/CompoundMethodTransform.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/CompoundMethodTransform.java deleted file mode 100644 index 580fadc2..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/CompoundMethodTransform.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation; - -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.api.*; -import org.sinytra.adapter.patch.util.MethodTransformBuilderImpl; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Supplier; - -// TODO Convert into universal operations interface to avoid using raw constructors -public class CompoundMethodTransform implements MethodTransform { - private final List transforms; - private final List> onSuccess; - private final List> onFail; - - private CompoundMethodTransform(List transforms) { - this(transforms, List.of(), List.of(), List.of()); - } - - private CompoundMethodTransform(List transforms, List> onSuccess, List> onFail, List filters) { - this.transforms = transforms; - this.onSuccess = onSuccess; - this.onFail = onFail; - } - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - Patch.Result result = this.transforms.stream() - .reduce(Patch.Result.PASS, (a, b) -> a.or(b.apply(methodContext)), Patch.Result::or); - for (Supplier supplier : result == Patch.Result.PASS ? this.onFail : this.onSuccess) { - result = result.or(supplier.get().apply(methodContext)); - } - return result; - } - - public static Builder builder(MethodTransform transform) { - return new Builder(List.of(transform)); - } - - public static Builder builder(List transforms) { - return new Builder(transforms); - } - - private static class BundleBuilder extends MethodTransformBuilderImpl.ClassImpl { - private List build() { - return this.transforms; - } - } - - public static Builder builder(Consumer> consumer) { - BundleBuilder builder = new BundleBuilder(); - consumer.accept(builder); - return new Builder(builder.build()); - } - - public static class Builder { - private final List transforms; - private final List> onSuccess = new ArrayList<>(); - private final List> onFail = new ArrayList<>(); - private final List filters = new ArrayList<>(); - - private Builder(List transforms) { - this.transforms = transforms; - } - - public Builder onSuccess(Supplier onSuccess) { - this.onSuccess.add(onSuccess); - return this; - } - - public Builder onSuccess(Consumer> consumer) { - BundleBuilder builder = new BundleBuilder(); - consumer.accept(builder); - this.onSuccess.add(() -> new CompoundMethodTransform(builder.build())); - return this; - } - - public Builder onFail(Supplier onFail) { - this.onFail.add(onFail); - return this; - } - - public Builder filter(MethodTransformFilter filter) { - this.filters.add(filter); - return this; - } - - public Builder filter(List filter) { - this.filters.addAll(filter); - return this; - } - - public CompoundMethodTransform build() { - return new CompoundMethodTransform(this.transforms, this.onSuccess, this.onFail, this.filters); - } - - public Patch.Result apply(MethodContext methodContext) { - return build().apply(methodContext); - } - } -} 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 5e3b269a..6ef83be5 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 @@ -1,6 +1,5 @@ package org.sinytra.adapter.patch.transformer.operation.param; -import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.TypeReference; @@ -11,20 +10,15 @@ import org.sinytra.adapter.patch.api.MixinConstants; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.transformer.ModifyArgsOffsetTransformer; +import org.sinytra.adapter.patch.transformer.ModifyArgsOffsetUpgrader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil.calculateLVTIndex; -import static org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil.extractWrapOperation; - -public record InjectParameterTransform(int index, Type type, boolean upgradeWrapOperation) implements ParameterTransformer { - public InjectParameterTransform(int index, Type type) { - this(index, type, true); - } +public record InjectParameterTransform(int index, Type type) implements ParameterTransformer { @Override public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { boolean isNonStatic = (methodNode.access & Opcodes.ACC_STATIC) == 0; @@ -46,7 +40,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont } if (annotation.matchesDesc(MixinConstants.MODIFY_ARGS)) { - ModifyArgsOffsetTransformer.modify(methodNode, List.of(Pair.of(this.index, this.type))); + ModifyArgsOffsetUpgrader.upgradeAfterParamInsert(methodNode, this.index); return Patch.Result.APPLY; } @@ -64,11 +58,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont methodNode.localVariables.add(index + (isNonStatic ? 1 : 0), new LocalVariableNode(newParameter.name, type.getDescriptor(), null, self.start, self.end, lvtIndex)); }); - if (this.upgradeWrapOperation) { - extractWrapOperation(methodContext, methodNode, parameters, wrapOpModification -> wrapOpModification - .insertParameter(index, nodes -> nodes.add(new VarInsnNode(Opcodes.ALOAD, lvtIndex)))); - } - return Patch.Result.APPLY; } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformationUtil.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformationUtil.java index c922fe2f..6f261224 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformationUtil.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformationUtil.java @@ -1,22 +1,19 @@ package org.sinytra.adapter.patch.transformer.operation.param; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.function.Consumer; public final class ParamTransformationUtil { private static final MethodQualifier WO_ORIGINAL_CALL = new MethodQualifier("Lcom/llamalad7/mixinextras/injector/wrapoperation/Operation;", "call", "([Ljava/lang/Object;)Ljava/lang/Object;"); @@ -50,219 +47,14 @@ public static List findWrapOperationOriginalCall(MethodNode me return List.of(); } - public static List findWrapOperationOriginalCallArgs(MethodNode methodNode, MethodContext methodContext) { - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { + public static List findWrapOperationOriginalCallArgs(MethodNode methodNode, MixinContext context) { + if (context.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { for (AbstractInsnNode insn : methodNode.instructions) { if (insn instanceof MethodInsnNode minsn && WO_ORIGINAL_CALL.matches(minsn)) { - return MethodCallAnalyzer.findFullMethodCallParamInsns(methodNode, minsn); + return MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); } } } return List.of(); } - - @SuppressWarnings("DuplicatedCode") // The duplication is small - public static void extractWrapOperation(final MethodContext methodContext, final MethodNode methodNode, final List params, final Consumer modification) { - AnnotationHandle annotation = methodContext.methodAnnotation(); - if (!annotation.matchesDesc(MixinConstants.WRAP_OPERATION)) { - return; - } - - var wrapOpIndex = -1; - for (int i = 0; i < params.size(); i++) { - if (params.get(i).getInternalName().equals(MixinConstants.OPERATION_INTERNAL_NAME)) { - wrapOpIndex = i; - break; - } - } - - if (wrapOpIndex < 0) { - return; - } - - boolean isNonStatic = (methodNode.access & Opcodes.ACC_STATIC) == 0; - - int wrapOpLvt = isNonStatic ? 1 : 0; - for (int i = 0; i < wrapOpIndex; i++) { - wrapOpLvt += params.get(i).getSize(); - } - - for (int i = 0; i < methodNode.instructions.size(); i++) { - var insn = methodNode.instructions.get(i); - - // A lot of assumptions ahead, beware. Here be dragons - if (insn instanceof MethodInsnNode minsn && WO_ORIGINAL_CALL.matches(minsn)) { - // Backtrace until we find the load instruction of the operation var - int loadInsnIndex = -1; - for (int j = i - 1; j >= 0; j--) { - if (methodNode.instructions.get(j) instanceof VarInsnNode vin && vin.var == wrapOpLvt && vin.getOpcode() == Opcodes.ALOAD) { - loadInsnIndex = j; - break; - } - } - if (loadInsnIndex == -1) { - return; - } - - // 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 - )) { - return; - } - - final IntList removals = new IntArrayList(); - final Map> insertions = new HashMap<>(); - final Map> replacements = new HashMap<>(); - modification.accept(new WrapOpModification() { - @Override - public void insertParameter(int index, Consumer adapter) { - insertions.put(index, adapter); - } - - @Override - public void replaceParameter(int index, Consumer adapter) { - replacements.put(index, adapter); - } - - @Override - public void removeParameter(int index) { - removals.add(index); - } - }); - - final int oldArraySize = AdapterUtil.getIntConstValue(methodNode.instructions.get(loadInsnIndex + 1)).getAsInt(); - int newArrayLength = oldArraySize + insertions.size(); - - methodNode.instructions.set(methodNode.instructions.get(loadInsnIndex + 1), AdapterUtil.getIntConstInsn(newArrayLength - removals.size())); - - List[] objects = new List[newArrayLength]; - for (int j = 0; j < newArrayLength; j++) objects[j] = new ArrayList<>(); - - // Find sequences of "PUSH//AASTORE/DUP" which represent the values of the vararg array - int currentSequenceIndex = -1; - // Skip the PUSH/ANEWARRAY/DUP for the array creation - for (int j = loadInsnIndex + 4; j < i; j++) { - final var instruction = methodNode.instructions.get(j); - final var possibleIdx = AdapterUtil.getIntConstValue(instruction); - if (currentSequenceIndex == -1 && possibleIdx.isPresent()) { - currentSequenceIndex = possibleIdx.getAsInt(); - continue; - } - if (currentSequenceIndex != -1) { - if (instruction.getOpcode() == Opcodes.AASTORE && (methodNode.instructions.get(j + 1).getOpcode() == Opcodes.DUP || currentSequenceIndex + 1 == oldArraySize)) { - j++; - currentSequenceIndex = -1; - continue; - } - - objects[currentSequenceIndex].add(instruction); - } - } - - int finalLoadInsnIndex = loadInsnIndex; - insertions.forEach((position, target) -> { - if (position > 0) { - final var lastOfPrevious = methodNode.instructions.indexOf(objects[position - 1].getLast()); - if (methodNode.instructions.get(lastOfPrevious + 2).getOpcode() != Opcodes.DUP) { - methodNode.instructions.insert(methodNode.instructions.get(lastOfPrevious + 1), new InsnNode(Opcodes.DUP)); - } - } - - if (!objects[position].isEmpty()) { - for (int j = newArrayLength - 1; j >= position; j--) { - objects[j] = objects[j - 1]; - objects[j - 1] = new ArrayList<>(); - if (!objects[j].isEmpty()) { - methodNode.instructions.set(methodNode.instructions.get(methodNode.instructions.indexOf(objects[j].getFirst()) - 1), AdapterUtil.getIntConstInsn(j)); - } - } - } - - final InsnList actualInstructions = new InsnList(); - actualInstructions.add(AdapterUtil.getIntConstInsn(position)); - final InsnList sub = new InsnList(); - target.accept(sub); - actualInstructions.add(sub); - actualInstructions.add(new InsnNode(Opcodes.AASTORE)); - if (position < newArrayLength - 1) { // Last element doesn't need a DUP - actualInstructions.add(new InsnNode(Opcodes.DUP)); - } - - final int insertionTarget; - if (position == 0) { - // Inject after the DUP of the array - insertionTarget = finalLoadInsnIndex + 3; - } else { - insertionTarget = methodNode.instructions.indexOf(objects[position - 1].getLast()) + 2; - } - - methodNode.instructions.insert(methodNode.instructions.get(insertionTarget), actualInstructions); - - sub.forEach(objects[position]::add); - }); - - replacements.forEach((position, cons) -> { - if (objects[position].isEmpty()) { - return; - } - - final InsnList actualInstructions = new InsnList(); - actualInstructions.add(AdapterUtil.getIntConstInsn(position)); - final InsnList sub = new InsnList(); - cons.accept(sub); - actualInstructions.add(sub); - actualInstructions.add(new InsnNode(Opcodes.ASTORE)); - actualInstructions.add(new InsnNode(Opcodes.DUP)); - final var target = methodNode.instructions.get(methodNode.instructions.indexOf(objects[position].getFirst()) - 1); - objects[position].forEach(methodNode.instructions::remove); - objects[position].clear(); - methodNode.instructions.insert(target, actualInstructions); - - sub.forEach(objects[position]::add); - }); - - - removals.forEach(position -> { - final var toRemove = objects[position]; - for (int j = position + 1; j < newArrayLength; j++) { - objects[j - 1] = objects[j]; - if (!objects[j - 1].isEmpty()) { - methodNode.instructions.set(methodNode.instructions.get(methodNode.instructions.indexOf(objects[j - 1].getFirst()) - 1), AdapterUtil.getIntConstInsn(j - 1)); - } - } - - final AbstractInsnNode dup = methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.getLast()) + 2); - List.of( - methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.getFirst()) - 1), - methodNode.instructions.get(methodNode.instructions.indexOf(toRemove.getLast()) + 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].getLast()); - 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 - i = methodNode.instructions.indexOf(minsn); - } - } - } - - public 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/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java index ac367d72..48477bc5 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 @@ -12,9 +12,7 @@ import java.util.List; -import static org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil.extractWrapOperation; - -public record RemoveParameterTransformer(int index, boolean upgradeWrapOperation) implements ParameterTransformer { +public record RemoveParameterTransformer(int index, boolean invalidateUsage) implements ParameterTransformer { public RemoveParameterTransformer(int index) { this(index, true); } @@ -24,11 +22,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont final int target = this.index() + offset; final int lvtIndex = ParamTransformationUtil.calculateLVTIndex(parameters, !methodContext.isStatic(), target); - // Remove the use of the param in a wrapop first to avoid the new LVT messing with the outcome of that - if (this.upgradeWrapOperation) { - extractWrapOperation(methodContext, methodNode, parameters, op -> op.removeParameter(target)); - } - LVTSnapshot.with(methodNode, () -> { LocalVariableNode lvn = methodNode.localVariables.stream() .filter(v -> v.index == lvtIndex) @@ -36,7 +29,9 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont .orElse(null); if (lvn != null) { methodNode.localVariables.remove(lvn); - AdapterUtil.replaceLVT(methodNode, idx -> idx == lvtIndex ? -1 : idx); + if (this.invalidateUsage) { + AdapterUtil.replaceLVT(methodNode, idx -> idx == lvtIndex ? -1 : idx); + } } }); 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 28feaa9f..881cf5d2 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 @@ -4,7 +4,8 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameters; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; @@ -60,7 +61,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont TypeAdapter typeFix = bfu.getTypeAdapter(type, originalType); // If this is a wrap operation, make an educated guess and try adapting the instance type if (typeFix == null && methodContext.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { - List params = MethodParameters.getParameterTypes(methodNode.desc); + List params = Parameters.getParameterTypes(methodNode.desc); if (!params.isEmpty()) { typeFix = bfu.getTypeAdapter(params.getFirst(), originalType); if (typeFix != null) { @@ -75,19 +76,12 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont } if (insn instanceof MethodInsnNode minsn && minsn.owner.equals(originalType.getInternalName())) { + List insns = MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); // Find var load instruction - AbstractInsnNode previous = minsn.getPrevious(); - if (previous != null) { - do { - // Limit scope to the current label / line only - if (previous instanceof LabelNode || previous instanceof LineNumberNode) { - break; - } - if (previous instanceof VarInsnNode varinsn && varinsn.var == localVar.index) { - minsn.owner = type.getInternalName(); - break; - } - } while ((previous = previous.getPrevious()) != null); + for (AbstractInsnNode callInsn : insns) { + if (callInsn instanceof VarInsnNode varinsn && varinsn.var == localVar.index) { + minsn.owner = this.type.getInternalName(); + } } } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ExtractMixin.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ExtractMixin.java index cab6ee3d..c62270bf 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ExtractMixin.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ExtractMixin.java @@ -333,8 +333,7 @@ private static Patch.Result recreateLocalVariables(ClassNode classNode, MethodNo // Load parameters for (int i = 0; i < paramLocalStart + 1; i++) { Type type = Type.getType(table.getByIndex(i).desc); - int opcode = OpcodeUtil.getLoadOpcode(type.getSort()); - replacementInsns.add(new VarInsnNode(opcode, i)); + replacementInsns.add(AdapterUtil.loadType(type, i)); } // Load recreated locals used.forEach(ordinal -> { diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java index 68114455..115c266c 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java @@ -5,12 +5,14 @@ import org.objectweb.asm.tree.MethodNode; 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.transformer.MethodUpgrader; +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 static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_SHIFT; -public record ModifyInjectionPoint(@Nullable String value, String target, boolean resetValues, boolean dontUpgrade) implements MethodTransform { +public record ModifyInjectionPoint(@Nullable String value, String target, boolean resetValues) implements MethodTransform { @Override public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { AnnotationHandle annotation = methodContext.injectionPointAnnotation(); @@ -19,21 +21,12 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont return Patch.Result.PASS; } if (this.value != null) { - AnnotationValueHandle handle = annotation.getValue("value").orElseThrow(() -> new IllegalArgumentException("Missing value handle")); + AnnotationValueHandle handle = annotation.getValue("value") + .orElseThrow(() -> new IllegalArgumentException("Missing value handle")); handle.set(this.value); } methodContext.recordAudit(this, "Change injection point to %s", this.target); - AnnotationValueHandle handle = annotation.getValue("target").orElse(null); - if (handle != null) { - String original = handle.get(); - handle.set(this.target); - // TODO Remove side effect - if (!this.dontUpgrade && !methodContext.methodAnnotation().matchesDesc(MixinConstants.MODIFY_EXPR_VAL)) { - MethodUpgrader.upgradeMethod(methodNode, methodContext, original, this.target); - } - } else { - annotation.appendValue("target", this.target); - } + annotation.setOrAppendNonNull("target", this.target); if (this.resetValues) { methodContext.methodAnnotation().removeValues("slice"); annotation.removeValues("ordinal", AT_SHIFT, "by", "opcode"); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java index 7782d074..bfc11d15 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java @@ -3,18 +3,12 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; 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.transformer.MethodUpgrader; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; -public record ModifyInjectionTarget(List replacementMethods, Action action) implements MethodTransform { - public ModifyInjectionTarget(List replacementMethods) { - this(replacementMethods, Action.OVERWRITE); - } - +public record ModifyInjectionTarget(List replacementMethods) implements MethodTransform { @Override public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { AnnotationHandle annotation = methodContext.methodAnnotation(); @@ -30,42 +24,11 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont .ifPresent(str -> methodNode.name = str); } else { annotation.>getValue("method").ifPresentOrElse( - handle -> { - List original = handle.get(); - this.action.handler.apply(handle, methodContext.matchingTargets(), this.replacementMethods); - if (original.size() == 1 && handle.get().size() == 1) { - // TODO Remove side effect - MethodUpgrader.upgradeMethod(methodNode, methodContext, original.getFirst(), handle.get().getFirst()); - } - }, + handle -> handle.set(this.replacementMethods), () -> annotation.appendValue("method", this.replacementMethods) ); } - if (methodContext.capturesLocals()) { - MethodUpgrader.upgradeCapturedLocals(methodNode, methodContext); - } - return Patch.Result.APPLY; } - - public enum Action { - ADD((handle, targets, replacements) -> handle.get().addAll(replacements)), - REPLACE((handle, targets, replacements) -> { - List value = handle.get(); - value.removeAll(targets); - value.addAll(replacements); - }), - OVERWRITE((handle, targets, replacements) -> handle.set(replacements)); - - private final TargetHandler handler; - - Action(TargetHandler handler) { - this.handler = handler; - } - } - - public interface TargetHandler { - void apply(AnnotationValueHandle> handle, List targets, List replacements); - } } \ No newline at end of file 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 fd4f6009..aba09ca4 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 @@ -8,6 +8,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.analysis.SourceValue; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; @@ -30,31 +31,16 @@ public final class AdapterUtil { public static final String LAMBDA_PREFIX = "lambda$"; private static final Pattern FIELD_REF_PATTERN = Pattern.compile("^(?L.+?;)?(?[^:]+)?:(?.+)?$"); - public static final Type CI_TYPE = Type.getObjectType("org/spongepowered/asm/mixin/injection/callback/CallbackInfo"); - public static final Type CIR_TYPE = Type.getObjectType("org/spongepowered/asm/mixin/injection/callback/CallbackInfoReturnable"); - public static final Type OPERATION_TYPE = Type.getObjectType(MixinConstants.OPERATION_INTERNAL_NAME); private static final Logger LOGGER = LogUtils.getLogger(); - public static int getLVTOffsetForType(Type type) { - return type.equals(Type.DOUBLE_TYPE) || type.equals(Type.LONG_TYPE) ? 2 : 1; + public static MethodNode copyMethod(MethodNode original) { + MethodNode copy = new MethodNode(original.access, original.name, original.desc, original.signature, original.exceptions.toArray(String[]::new)); + original.accept(copy); + return copy; } - public static int getLVTIndexForParam(MethodNode method, int paramIndex, Type type) { - Type[] paramTypes = Type.getArgumentTypes(method.desc); - int ordinal = 0; - for (int i = paramIndex - 1; i > 0; i--) { - if (type.equals(paramTypes[i])) { - ordinal++; - } - } - List locals = method.localVariables.stream() - .sorted(Comparator.comparingInt(lvn -> lvn.index)) - .filter(lvn -> lvn.desc.equals(type.getDescriptor())) - .toList(); - if (locals.size() > ordinal) { - return locals.get(ordinal).index; - } - return -1; + public static int getLVTOffsetForType(Type type) { + return type.equals(Type.DOUBLE_TYPE) || type.equals(Type.LONG_TYPE) ? 2 : 1; } public static String randomString(int length) { @@ -135,11 +121,17 @@ public static OptionalInt getIntConstValue(AbstractInsnNode insn) { if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) { return OptionalInt.of(((IntInsnNode) insn).operand); } + if (insn instanceof LdcInsnNode) { + Object cst = ((LdcInsnNode) insn).cst; + if (cst instanceof Integer) { + return OptionalInt.of((Integer) cst); + } + } return OptionalInt.empty(); } public static AbstractInsnNode getIntConstInsn(int value) { - if (value >= 1 && value <= 5) { + if (value >= 0 && value <= 5) { return new InsnNode(Opcodes.ICONST_0 + value); } else if (value > 5 && value <= 127) { return new IntInsnNode(Opcodes.BIPUSH, value); @@ -154,6 +146,11 @@ public static InsnList insnsWithAdapter(Consumer consumer) { return dummy.instructions; } + public static VarInsnNode loadType(Type type, int index) { + int opcode = OpcodeUtil.getLoadOpcode(type.getSort()); + return new VarInsnNode(opcode, index); + } + public static boolean isShadowField(FieldNode field) { return AdapterUtil.hasAnnotation(field.visibleAnnotations, MixinConstants.SHADOW); } @@ -193,20 +190,6 @@ public static List getAnnotatedParameters(MethodNode methodNode, Type[] p return list; } - public static boolean isParamAnnotated(MethodNode method, int index, String annotationDesc) { - if (method.invisibleParameterAnnotations != null && method.invisibleParameterAnnotations.length > index) { - List parameterAnnotations = method.invisibleParameterAnnotations[index]; - if (parameterAnnotations != null) { - for (AnnotationNode paramAnn : parameterAnnotations) { - if (annotationDesc.equals(paramAnn.desc)) { - return true; - } - } - } - } - return false; - } - @Nullable public static CapturedLocals getCapturedLocals(MethodNode methodNode, MethodContext methodContext) { AnnotationHandle annotation = methodContext.methodAnnotation(); @@ -236,7 +219,7 @@ public static CapturedLocals getCapturedLocals(MethodNode methodNode, MethodCont private static OptionalInt getCapturedLocalStartingIndex(Type[] params) { for (int i = 0; i < params.length; i++) { Type param = params[i]; - if ((param.equals(CI_TYPE) || param.equals(CIR_TYPE)) && i + 1 < params.length) { + if ((param.equals(MixinConstants.CI_TYPE) || param.equals(MixinConstants.CIR_TYPE)) && i + 1 < params.length) { return OptionalInt.of(i + 1); } } @@ -296,12 +279,16 @@ public static InsnList insnList(List insns) { return list; } - public static List cloneInsns(Collection insns) { - return insns.stream().map(i -> i.clone(Map.of())).toList(); + public static List subListInsnsExc(AbstractInsnNode from, AbstractInsnNode to) { + List list = new ArrayList<>(); + for (AbstractInsnNode insn = from; insn != null && insn != to; insn = insn.getNext()) { + list.add(insn); + } + return list; } - public static Type getMixinCallableReturnType(MethodNode method) { - return Type.getReturnType(method.desc) == Type.VOID_TYPE ? CI_TYPE : CIR_TYPE; + public static List cloneInsns(Collection insns) { + return insns.stream().map(i -> i.clone(Map.of())).toList(); } public static boolean allElementsEqual(Collection list, BiPredicate equalityFn) { @@ -311,6 +298,33 @@ public static boolean allElementsEqual(Collection list, BiPredicate .orElse(true); } + public static void replaceRangeInclusive(InsnList list, AbstractInsnNode start, AbstractInsnNode end, List replacement) { + InsnList newInsns = AdapterUtil.insnList(replacement); + list.insertBefore(start, newInsns); + + AbstractInsnNode current = start; + while (current != null) { + AbstractInsnNode next = current.getNext(); + list.remove(current); + + if (current == end) { + break; + } + current = next; + } + } + + @Nullable + public static AbstractInsnNode getSingleInsn(SourceValue value) { + return value.insns.size() == 1 ? value.insns.iterator().next() : null; + } + + @Nullable + public static AbstractInsnNode getSingleInsn(List values, int index) { + SourceValue value = values.get(index); + return getSingleInsn(value); + } + private AdapterUtil() { } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java b/definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java index d06fbde9..2fc91cc1 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java @@ -4,7 +4,10 @@ import org.sinytra.adapter.patch.api.MethodTransformBuilder; import org.sinytra.adapter.patch.transformer.ModifyVarUpgradeToModifyExprVal; import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; -import org.sinytra.adapter.patch.transformer.operation.unit.*; +import org.sinytra.adapter.patch.transformer.operation.unit.ExtractMixin; +import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionTarget; +import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMethodAccess; +import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMixinType; import java.util.ArrayList; import java.util.List; @@ -25,11 +28,6 @@ public T modifyTarget(String... methods) { return transform(new ModifyInjectionTarget(List.of(methods))); } - @Override - public T modifyTarget(ModifyInjectionTarget.Action action, String... methods) { - return transform(new ModifyInjectionTarget(List.of(methods), action)); - } - @Override public T modifyMethodAccess(ModifyMethodAccess.AccessChange... changes) { return transform(new ModifyMethodAccess(List.of(changes))); @@ -73,16 +71,4 @@ public T chain(Consumer consumer) { private T coerce() { return (T) this; } - - public static class ClassImpl> extends MethodTransformBuilderImpl implements MethodTransformBuilder.Class { - @Override - public T modifyInjectionPoint(String value, String target, boolean resetValues) { - return modifyInjectionPoint(value, target, resetValues, false); - } - - @Override - public T modifyInjectionPoint(String value, String target, boolean resetValues, boolean dontUpgrade) { - return transform(new ModifyInjectionPoint(value, target, resetValues, dontUpgrade)); - } - } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java index 7da3f188..e0ebfccd 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java @@ -49,8 +49,8 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont auditTrail.recordResult(methodContext, PatchAuditTrail.Match.NONE); MixinContext mixinContext = new MixinContext(classNode, methodNode, methodContext); - PipelineExecutor pipeline = new PipelineExecutor(mixinType, classTarget, mixinContext); - Patch.Result result = pipeline.execute(); + PipelineExecutor pipeline = new PipelineExecutor(classTarget, mixinContext); + Patch.Result result = pipeline.execute(mixinType); if (result != Patch.Result.PASS) { auditTrail.recordResult(methodContext, PatchAuditTrail.Match.FULL); return result; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java index f887fcdc..b0ccf524 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java @@ -10,6 +10,9 @@ public final class ConfigurationTemplates { public static final PropertyContainerTemplate MIXIN_AT = MIXIN_BASE.extend() .require(Keys.TARGET_AT) .build(); + public static final PropertyContainerTemplate DELETE = PropertyContainerTemplate.builder() + .require(Keys.DELETE) + .build(); private ConfigurationTemplates() { } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java b/definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java new file mode 100644 index 00000000..28c67f8f --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java @@ -0,0 +1,9 @@ +package org.sinytra.adapter.next.env; + +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; + +public class Configurations { + public static final Configuration DELETE = MutableConfiguration.create(ConfigurationTemplates.DELETE) + .setShouldDelete(true); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java b/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java index 84dcc8af..569ae9f2 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java @@ -1,19 +1,23 @@ package org.sinytra.adapter.next.env; import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.ctx.MethodHelper; +import org.sinytra.adapter.next.env.ctx.RefMapper; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.PatchContext; import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.provider.ClassLookup; -public class MixinContext { +public class MixinContext implements RefMapper { private final ClassNode classNode; private final MethodNode methodNode; + private final MethodNode originalMethodNode; private final MethodHelper methodHelper; private final MethodContext methodContext; @@ -23,6 +27,7 @@ public MixinContext(ClassNode classNode, MethodNode methodNode, MethodContext me this.methodNode = methodNode; this.methodHelper = new MethodHelper(this, methodContext.targetTypes()); this.methodContext = methodContext; + this.originalMethodNode = AdapterUtil.copyMethod(this.methodNode); } public ClassNode classNode() { @@ -33,6 +38,10 @@ public MethodNode methodNode() { return this.methodNode; } + public MethodNode unmodifiedMethodNode() { + return this.originalMethodNode; + } + public MethodHelper methods() { return this.methodHelper; } @@ -59,6 +68,7 @@ public TypeAdapter getTypeAdapter(Type from, Type to) { return this.methodContext.patchContext().environment().bytecodeFixerUpper().getTypeAdapter(from, to); } + @Override public String remap(String refmapEntry) { return patchContext().remap(refmapEntry); } @@ -67,6 +77,10 @@ public PatchContext patchContext() { return this.methodContext.patchContext(); } + public boolean isStatic() { + return MethodHelper.isStatic(this.methodNode); + } + @Deprecated public MethodContext legacy() { return this.methodContext; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java index f41c5873..8976815a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; -import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.RefMapper; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.MixinConstants; @@ -84,6 +84,10 @@ public AtData withTarget(String target) { return new AtData(this.value, target, this.ordinal); } + public AtData withOrdinal(Integer ordinal) { + return new AtData(this.value, target, ordinal); + } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; @@ -96,14 +100,14 @@ public int hashCode() { return Objects.hash(value, target, ordinal); } - public static Optional parse(AnnotationHandle annotation, MixinContext context) { + public static Optional parse(AnnotationHandle annotation, RefMapper mapper) { String value = annotation.getValue("value").map(AnnotationValueHandle::get).orElse(null); if (value == null) { return Optional.empty(); } String target = annotation.getValue("target").map(AnnotationValueHandle::get) - .map(context::remap) + .map(mapper::remap) .orElse(null); Integer ordinal = annotation.getValue("ordinal").map(AnnotationValueHandle::get).orElse(null); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java new file mode 100644 index 00000000..141980dd --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java @@ -0,0 +1,24 @@ +package org.sinytra.adapter.next.env.ann; + +import org.objectweb.asm.Type; +import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; + +public class ConstantData { + private Object value; + + public ConstantData(Object value) { + this.value = value; + } + + public static ConstantData classValue(Type value) { + return new ConstantData(value); + } + + public void apply(AnnotationHandle handle) { + if (this.value instanceof Type) { + handle.setOrAppendNonNull("classValue", this.value); + } else { + throw new IllegalStateException("Unexpected value: " + value); + } + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/InjectMixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/InjectMixinData.java deleted file mode 100644 index dc74c054..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/InjectMixinData.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.sinytra.adapter.next.env.ann; - -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.List; -import java.util.Objects; - -public class InjectMixinData extends MixinData { - private final List slice; - - public InjectMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, List slice) { - super(targetClass, targetMethod, atData); - - this.slice = Objects.requireNonNull(slice); - } - - public List getSlice() { - return this.slice; - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java index 15c39432..75b8f423 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java @@ -9,8 +9,9 @@ public class MixinAnnotationConstants { public static final String AT_VAL_SINYTRA_INSTANCEOF = "sinytra:INSTANCEOF"; public static final String AT_SHIFT = "shift"; + public static final String PROPERTY_AT = "at"; + public static final String PROPERTY_CONSTANT = "constant"; public static final String PROPERTY_ORDINAL = "ordinal"; - public static final String PROPERTY_INDEX = "index"; public static final String PROPERTY_SLICE = "slice"; public static final String SLICE_FROM = "from"; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java index 29a887d9..6899e0f1 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java @@ -1,16 +1,23 @@ package org.sinytra.adapter.next.env.ann; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainer; +import org.sinytra.adapter.next.pipeline.config.PropertyKey; import org.sinytra.adapter.patch.util.MethodQualifier; -public abstract class MixinData { +import java.util.Optional; + +public class MixinData { private final ClassTarget targetClass; private final MethodQualifier targetMethod; private final AtData atData; + private final PropertyContainer properties; - public MixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData) { + public MixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, PropertyContainer properties) { this.targetClass = targetClass; this.targetMethod = targetMethod; this.atData = atData; + this.properties = properties; } public String getTargetClass() { @@ -24,4 +31,12 @@ public MethodQualifier getTargetMethod() { public AtData at() { return this.atData; } + + public Optional getProperty(PropertyKey key) { + return this.properties.getProperty(key); + } + + public boolean isCancellable() { + return getProperty(Configuration.Keys.CANCELLABLE).orElse(false); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyArgMixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyArgMixinData.java deleted file mode 100644 index b558f03c..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyArgMixinData.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.sinytra.adapter.next.env.ann; - -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.OptionalInt; - -public class ModifyArgMixinData extends MixinData { - private Integer index; - - public ModifyArgMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, Integer index) { - super(targetClass, targetMethod, atData); - - this.index = index; - } - - public OptionalInt index() { - return this.index != null ? OptionalInt.of(this.index) : OptionalInt.empty(); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyExpressionValueMixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyExpressionValueMixinData.java deleted file mode 100644 index 4559d4cc..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyExpressionValueMixinData.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.sinytra.adapter.next.env.ann; - -import org.sinytra.adapter.patch.util.MethodQualifier; - -public class ModifyExpressionValueMixinData extends MixinData { - public ModifyExpressionValueMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData) { - super(targetClass, targetMethod, atData); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java deleted file mode 100644 index af1a0565..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ModifyVariableMixinData.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.sinytra.adapter.next.env.ann; - -import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.OptionalInt; - -public class ModifyVariableMixinData extends MixinData { - private final boolean argsOnly; - private final Integer ordinal; - @Nullable - private final SliceData slice; - - public ModifyVariableMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, boolean argsOnly, Integer ordinal, @Nullable SliceData slice) { - super(targetClass, targetMethod, atData); - - this.argsOnly = argsOnly; - this.ordinal = ordinal; - this.slice = slice; - } - - public boolean argsOnly() { - return this.argsOnly; - } - - public OptionalInt ordinal() { - return this.ordinal != null ? OptionalInt.of(this.ordinal) : OptionalInt.empty(); - } - - @Nullable - public SliceData slice() { - return this.slice; - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/RedirectMixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/RedirectMixinData.java deleted file mode 100644 index 6f1b6d85..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/RedirectMixinData.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.sinytra.adapter.next.env.ann; - -import org.sinytra.adapter.patch.util.MethodQualifier; - -public class RedirectMixinData extends MixinData { - public RedirectMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData) { - super(targetClass, targetMethod, atData); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java index 83619ba6..32644cbb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java @@ -3,12 +3,10 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.tree.AnnotationNode; -import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.RefMapper; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.api.MixinConstants; -import javax.management.AttributeNotFoundException; - import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.SLICE_FROM; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.SLICE_TO; @@ -33,7 +31,7 @@ public AtData to() { return this.to; } - public static SliceData parse(AnnotationHandle handle, MixinContext context) { + public static SliceData parse(AnnotationHandle handle, RefMapper context) { AtData from = handle.getNested(SLICE_FROM) .flatMap(s -> AtData.parse(s, context)) .orElse(null); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/WrapOperationMixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/WrapOperationMixinData.java deleted file mode 100644 index a63b08a0..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/WrapOperationMixinData.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.sinytra.adapter.next.env.ann; - -import org.sinytra.adapter.patch.util.MethodQualifier; - -public class WrapOperationMixinData extends MixinData { - public WrapOperationMixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData) { - super(targetClass, targetMethod, atData); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java index f5de93a4..c700e433 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java @@ -7,12 +7,15 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.patch.analysis.InheritanceHandler; import org.sinytra.adapter.patch.api.MethodContext.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.slf4j.Logger; +import java.util.Collection; import java.util.List; +import java.util.stream.Stream; public class MethodFinder { private static final Logger LOGGER = LogUtils.getLogger(); @@ -29,6 +32,21 @@ public MethodFinder(String fallbackOwner) { this.fallbackOwner = fallbackOwner; } + @Nullable + public TargetPair findInheritedMethod(ClassLookup lookup, MethodQualifier qualifier) { + ClassNode node = lookup.getClass(qualifier.internalOwnerName()).orElse(null); + if (node == null) return null; + + // TODO Unify + Collection parents = new InheritanceHandler(lookup).getClassParents(node.name); + + return Stream.concat(Stream.of(node.name), parents.stream()) + .flatMap(cls -> lookup.findMethod(cls, qualifier.name(), qualifier.desc()).stream() + .map(m -> new TargetPair(lookup.getClass(cls).orElseThrow(), m))) + .findFirst() + .orElse(null); + } + @Nullable public TargetPair findMethod(ClassLookup lookup, MethodQualifier qualifier, int flags) { Pair> pair = findMethods(lookup, qualifier, flags); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java index d63cd717..ef6080dc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java @@ -7,8 +7,8 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.ParamDiffResolver; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; @@ -30,8 +30,7 @@ import java.util.function.BiFunction; import java.util.function.Supplier; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_SHIFT; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.*; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; public class MethodHelper { @@ -50,8 +49,8 @@ public MethodHelper(MixinContext context, List targetTypes) { } @Nullable - public MethodNode findMethod(ClassLookup lookup, MethodQualifier qualifier) { - return Optional.ofNullable(findMethodPair(lookup, qualifier)) + public MethodNode findInheritedMethod(ClassLookup lookup, MethodQualifier qualifier) { + return Optional.ofNullable(this.methodFinder.findInheritedMethod(lookup, qualifier)) .map(TargetPair::methodNode) .orElse(null); } @@ -89,31 +88,42 @@ public AbstractInsnNode findInjectionTargetInsn(@Nullable MethodContext.TargetPa } public List findInjectionTargetInsns(@Nullable MethodContext.TargetPair target) { - return this.targetInstructionsCache.computeIfAbsent(target, this::computeInjectionTargetInsns); + return findInjectionTargetInsns(target, false); } - private List computeInjectionTargetInsns(@Nullable MethodContext.TargetPair target) { + public List findInjectionTargetInsns(@Nullable MethodContext.TargetPair target, boolean ignoreOrdinal) { + return this.targetInstructionsCache.computeIfAbsent(target, t -> computeInjectionTargetInsns(t, ignoreOrdinal)); + } + + private List computeInjectionTargetInsns(@Nullable MethodContext.TargetPair target, boolean ignoreOrdinal) { return computeInjectionTargetInsns( target, this.context::injectionPointAnnotation, - (ctx, h) -> InjectionPoint.parse(ctx, this.context.methodNode(), this.context.methodAnnotation().unwrap(), h.unwrap()), + (ctx, h) -> { + AnnotationHandle atAnn = h; + if (ignoreOrdinal) { + atAnn = atAnn.copy(); + atAnn.removeValues(PROPERTY_ORDINAL); + } + + return InjectionPoint.parse(ctx, this.context.methodNode(), this.context.methodAnnotation().unwrap(), atAnn.unwrap()); + }, true ); } public List resolveCapturedMethodParams(Configuration clean, Configuration dirty) { - List cleanCaptured = clean.getParameters().get(CAPTURED_PARAMS); + List cleanCaptured = clean.getParameters().getTypes(CAPTURED_PARAMS); List dirtyCaptured = new ArrayList<>(); // Evaluate parameter difference, capture additional params when necessary if (!cleanCaptured.isEmpty()) { - // TODO Clean up boilerplate MethodNode cleanTarget = findOwnMethod(this.context.cleanLookup(), clean.getTargetMethod()); MethodNode dirtyTarget = findOwnMethod(this.context.dirtyLookup(), dirty.getTargetMethod()); if (cleanTarget == null || dirtyTarget == null) return dirtyCaptured; LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.compareMethodParameters(cleanTarget, dirtyTarget); - List cleanTargetParams = MethodParameters.getParameterTypes(cleanTarget.desc); + List cleanTargetParams = Parameters.getParameterTypes(cleanTarget.desc); // Use a sublist instead of cleanCaptured to be able to compare Type instances directly List capturedSublist = cleanTargetParams.subList(0, cleanCaptured.size()); // Expect cleanTargetParams to begin with or be equal to cleanCaptured @@ -131,7 +141,7 @@ public List resolveCapturedMethodParams(Configuration clean, Configuration .orElse(-1); if (maxIndex != -1) { - List dirtyTargetParams = MethodParameters.getParameterTypes(dirtyTarget.desc); + List dirtyTargetParams = Parameters.getParameterTypes(dirtyTarget.desc); dirtyCaptured = List.copyOf(dirtyTargetParams.subList(0, maxIndex + 1)); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefMapper.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefMapper.java new file mode 100644 index 00000000..d006a70b --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefMapper.java @@ -0,0 +1,5 @@ +package org.sinytra.adapter.next.env.ctx; + +public interface RefMapper { + String remap(String refmapEntry); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Annotation.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/Annotation.java new file mode 100644 index 00000000..6e6557de --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/Annotation.java @@ -0,0 +1,79 @@ +package org.sinytra.adapter.next.env.param; + +import com.google.common.collect.ImmutableMap; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.tree.AnnotationNode; + +import java.util.HashMap; +import java.util.Map; + +public class Annotation { + private final String desc; + private final boolean visible; + private final Map properties; + + public Annotation(String desc, boolean visible, Map properties) { + this.desc = desc; + this.visible = visible; + this.properties = ImmutableMap.copyOf(properties); + } + + public void accept(AnnotationVisitor visitor) { + this.properties.forEach(visitor::visit); + } + + public AnnotationNode toAnnotationNode() { + AnnotationNode node = new AnnotationNode(this.desc); + this.properties.forEach(node::visit); + return node; + } + + public String getDesc() { + return this.desc; + } + + public boolean isVisible() { + return this.visible; + } + + public static Annotation parse(AnnotationNode node, boolean visible) { + Builder builder = builder(node.desc).visible(visible); + if (node.values != null) { + for (int i = 0; i + 1 < node.values.size(); i += 2) { + String name = (String) node.values.get(i); + Object value = node.values.get(i + 1); + + builder.put(name, value); + } + } + return builder.build(); + } + + public static Builder builder(String desc) { + return new Builder(desc); + } + + public static class Builder { + private final String desc; + private boolean visible = false; + private final Map properties = new HashMap<>(); + + public Builder(String desc) { + this.desc = desc; + } + + public Builder put(String name, Object value) { + this.properties.put(name, value); + return this; + } + + public Builder visible(boolean visible) { + this.visible = visible; + return this; + } + + public Annotation build() { + return new Annotation(this.desc, this.visible, this.properties); + } + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Copiable.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/Copiable.java new file mode 100644 index 00000000..313e8ac8 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/Copiable.java @@ -0,0 +1,5 @@ +package org.sinytra.adapter.next.env.param; + +public interface Copiable { + T copy(); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java index ebfd7719..2389456e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java @@ -1,83 +1,125 @@ package org.sinytra.adapter.next.env.param; +import com.google.common.collect.ImmutableMap; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.*; import java.util.function.Predicate; -public class MethodParameters { +public class MethodParameters implements Copiable { + public enum ParamGroupType { SINGLE, VARIABLE } - public record ParamInfo(Type type, boolean isLocal) { - } - - public record ParamGroup(ParamGroupType type, String name, Predicate predicate) { + public record ParamGroup(ParamGroupType type, String name, Predicate predicate) { public static final ParamGroup METHOD_PARAMS = new ParamGroup(ParamGroupType.VARIABLE, "method_params", i -> true); public static final ParamGroup CAPTURED_PARAMS = new ParamGroup(ParamGroupType.VARIABLE, "captured_params", i -> !i.isLocal()); public static final ParamGroup SINGLE_ANY = new ParamGroup(ParamGroupType.SINGLE, "single_any", i -> true); - public static final ParamGroup CI_CIR = new ParamGroup(ParamGroupType.SINGLE, "ci_cir", i -> i.type().equals(AdapterUtil.CI_TYPE) || i.type().equals(AdapterUtil.CIR_TYPE)); - public static final ParamGroup OPERATION = new ParamGroup(ParamGroupType.SINGLE, "operation", i -> i.type().equals(AdapterUtil.OPERATION_TYPE)); + public static final ParamGroup CI_CIR = new ParamGroup(ParamGroupType.SINGLE, "ci_cir", i -> i.getType().equals(MixinConstants.CI_TYPE) || i.getType().equals(MixinConstants.CIR_TYPE)); + public static final ParamGroup OPERATION = new ParamGroup(ParamGroupType.SINGLE, "operation", i -> i.getType().equals(MixinConstants.OPERATION_TYPE)); - public static final ParamGroup LOCALS = new ParamGroup(ParamGroupType.VARIABLE, "locals", ParamInfo::isLocal); + public static final ParamGroup LOCALS = new ParamGroup(ParamGroupType.VARIABLE, "locals", Parameter::isLocal); } - private final Map> groups; + private final Map> groups; private final List order; + private final Map mapping; - private MethodParameters(Map> groups, List order) { - this.groups = new HashMap<>(groups); + private MethodParameters(Map> groups, List order) { + this(groups, order, new HashMap<>()); + } + + private MethodParameters(Map> groups, List order, Map mapping) { + this.groups = new HashMap<>(); + groups.forEach((k,v) -> this.groups.put(k, new ArrayList<>(v))); + this.order = order; + this.mapping = mapping; + } + + public List getOrder() { + return this.order; + } + + public void mapParameter(Parameter old, Parameter replacement) { + this.mapping.put(old, replacement); } public boolean has(ParamGroup group) { return this.groups.containsKey(group); } - public List get(ParamGroup group) { + public List getTypes(ParamGroup group) { + return get(group).stream() + .map(Parameter::getType) + .toList(); + } + + public List get(ParamGroup group) { return Objects.requireNonNull(this.groups.get(group), "Group %s is not available".formatted(group.name())); } - public void set(ParamGroup group, List params) { + public void add(ParamGroup group, Parameter param) { + if (this.groups.containsKey(group)) { + this.groups.get(group).add(param); + } + } + + public void set(ParamGroup group, Parameter param) { + set(group, List.of(param)); + } + + public void setTypes(ParamGroup group, List params) { + set(group, params.stream().map(Parameter::simple).toList()); + } + + public void set(ParamGroup group, List params) { if (!this.groups.containsKey(group)) { throw new IllegalArgumentException("Group %s is not available".formatted(group.name())); } - this.groups.put(group, params); + this.groups.put(group, new ArrayList<>(params)); + } + + public List mergeTypes() { + return merge().stream() + .map(Parameter::getType) + .toList(); } - public List merge() { - List result = new ArrayList<>(); + public List merge() { + List result = new ArrayList<>(); for (ParamGroup group : this.order) { - result.addAll(this.groups.get(group)); + result.addAll(get(group)); } return result; } - public static List getParameterTypes(String desc) { - return Arrays.asList(Type.getArgumentTypes(desc)); + public Map getMapping() { + return ImmutableMap.copyOf(this.mapping); } - private static List getParamInfo(MethodNode method) { - List params = getParameterTypes(method.desc); - List infos = new ArrayList<>(); - for (int i = 0; i < params.size(); i++) { - infos.add(new ParamInfo(params.get(i), AdapterUtil.isParamAnnotated(method, i, MixinConstants.LOCAL))); - } - return infos; + @Override + public MethodParameters copy() { + Map> groups = new HashMap<>(); + this.groups.forEach((group, params) -> groups.put(group, new ArrayList<>(params))); + + List order = new ArrayList<>(this.order); + Map mapping = new HashMap<>(this.mapping); + return new MethodParameters(groups, order, mapping); } public static MethodParameters create(MethodNode method, List groups) { - return create(getParamInfo(method), groups); + List parameters = Parameters.parse(method); + return create(parameters, groups); } - private static MethodParameters create(List params, List groups) { - Map> results = new HashMap<>(); + private static MethodParameters create(List params, List groups) { + Map> results = new HashMap<>(); for (ParamGroup type : groups) { results.put(type, new ArrayList<>()); } @@ -88,15 +130,15 @@ private static MethodParameters create(List params, List ParamGroup group = groups.get(groupIndex); ParamGroup nextGroup = groupIndex + 1 < groups.size() ? groups.get(groupIndex + 1) : null; - ParamInfo param = params.get(paramIndex); - List output = results.get(group); + Parameter param = params.get(paramIndex); + List output = results.get(group); if (group.type() == ParamGroupType.SINGLE) { if (!group.predicate().test(param)) { throw new IllegalStateException("Unexpected single parameter: " + param); } - output.add(param.type()); + output.add(param); paramIndex++; groupIndex++; } else if (group.type() == ParamGroupType.VARIABLE) { @@ -109,11 +151,11 @@ private static MethodParameters create(List params, List // Two subsequent groups cannot both match a parameter else { throw new IllegalStateException("Ambiguous match for param %s in groups %s and %s" - .formatted(param.type(), group.name(), groups.get(groupIndex + 1).name())); + .formatted(param.getType(), group.name(), groups.get(groupIndex + 1).name())); } } - output.add(param.type()); + output.add(param); paramIndex++; } else { groupIndex++; @@ -129,14 +171,22 @@ public static Builder builder() { } public static class Builder { - private final Map> groups = new HashMap<>(); + private final Map> groups = new HashMap<>(); private final List order = new ArrayList<>(); - public Builder put(ParamGroup group, Type param) { + public Builder putType(ParamGroup group, Type param) { + return put(group, Parameter.simple(param)); + } + + public Builder put(ParamGroup group, Parameter param) { return put(group, List.of(param)); } - public Builder put(ParamGroup group, List params) { + public Builder putTypes(ParamGroup group, List params) { + return put(group, params.stream().map(Parameter::simple).toList()); + } + + public Builder put(ParamGroup group, List params) { if (this.order.contains(group)) { throw new IllegalStateException("Duplicate group " + group); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java new file mode 100644 index 00000000..d4084b89 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java @@ -0,0 +1,72 @@ +package org.sinytra.adapter.next.env.param; + +import com.google.common.collect.ImmutableList; +import org.objectweb.asm.Type; +import org.sinytra.adapter.patch.api.MixinConstants; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class Parameter { + private final Type type; + private final List annotations; + + public Parameter(Type type, List annotations) { + this.type = type; + this.annotations = ImmutableList.copyOf(annotations); + } + + public Type getType() { + return this.type; + } + + public List getAnnotations() { + return this.annotations; + } + + public boolean isLocal() { + return hasAnnotation(MixinConstants.LOCAL); + } + + public boolean hasAnnotation(String desc) { + return this.annotations.stream() + .anyMatch(annotation -> annotation.getDesc().equals(desc)); + } + + public static Parameter simple(Type type) { + return new Parameter(type, List.of()); + } + + public static Builder builder(String typeDesc) { + return builder(Type.getType(typeDesc)); + } + + public static Builder builder(Type type) { + return new Builder(type); + } + + public static class Builder { + private final Type type; + private final List annotations = new ArrayList<>(); + + public Builder(Type type) { + this.type = type; + } + + public Builder annotate(String desc, Consumer consumer) { + Annotation.Builder builder = Annotation.builder(desc); + consumer.accept(builder); + return annotate(builder.build()); + } + + public Builder annotate(Annotation annotation) { + this.annotations.add(annotation); + return this; + } + + public Parameter build() { + return new Parameter(this.type, this.annotations); + } + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java new file mode 100644 index 00000000..6123aa75 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java @@ -0,0 +1,125 @@ +package org.sinytra.adapter.next.env.param; + +import com.mojang.datafixers.util.Pair; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.analysis.*; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.selector.FrameUtil; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class Parameters { + public static List parse(MethodNode method) { + List types = getParameterTypes(method.desc); + List parameters = new ArrayList<>(); + for (int i = 0; i < types.size(); i++) { + Type type = types.get(i); + Parameter.Builder builder = Parameter.builder(type); + parseAnnotations(builder, method.invisibleParameterAnnotations, false, i); + parseAnnotations(builder, method.visibleParameterAnnotations, true, i); + Parameter parameter = builder.build(); + + parameters.add(parameter); + } + return parameters; + } + + private static void parseAnnotations(Parameter.Builder builder, @Nullable List[] source, boolean visible, int index) { + if (source != null && source.length > index) { + List annotations = source[index]; + if (annotations != null) { + for (AnnotationNode node : annotations) { + Annotation parsed = Annotation.parse(node, visible); + builder.annotate(parsed); + } + } + } + } + + public static List getParameterTypes(String desc) { + return Arrays.asList(Type.getArgumentTypes(desc)); + } + + public static Map> gatherVarMappings(MethodNode method, List cleanParameters, List dirtyParameters, Map replacements) { + LocalVariableLookup lookup = new LocalVariableLookup(method); + Map> map = replacements.entrySet().stream() + .map(entry -> { + int oldIndex = cleanParameters.indexOf(entry.getKey()); + if (oldIndex == -1) return null; + + int newIndex = dirtyParameters.indexOf(entry.getValue()); + if (newIndex == -1) return null; + + LocalVariableNode oldVar = lookup.getByParameterOrdinal(oldIndex); + if (oldVar == null) return null; + + LocalVariableNode newVar = lookup.getByParameterOrdinal(newIndex); + if (newVar == null) return null; + + return Pair.of(oldVar.index, Pair.of(newVar.index, entry.getValue().getType())); + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)); + + Map> varMap = new HashMap<>(); + for (AbstractInsnNode insn : method.instructions) { + if (insn instanceof VarInsnNode varInsn && map.containsKey(varInsn.var)) { + varMap.put(varInsn, map.get(varInsn.var)); + } + } + return varMap; + } + + public static void applyVarMappings(MethodNode methodNode, Map> map) { + map.forEach((i, v) -> retypeVariableAndReceivers(methodNode, i, v.getFirst(), v.getSecond().getInternalName())); + } + + public static void applyAnnotations(MethodNode method, List parameters) { + for (int i = 0; i < parameters.size(); i++) { + Parameter param = parameters.get(i); + + // TODO Always re-apply all annotations or? + // Remove old annotations + Set descs = param.getAnnotations().stream().map(Annotation::getDesc).collect(Collectors.toSet()); + final int finalI = i; + Stream.of(method.visibleParameterAnnotations, method.invisibleParameterAnnotations) + .filter(Objects::nonNull) + .map(arr -> arr[finalI]) + .filter(Objects::nonNull) + .forEach(list -> list.removeIf(n -> descs.contains(n.desc))); + + for (Annotation annotation : param.getAnnotations()) { + AnnotationVisitor visitor = method.visitParameterAnnotation(i, annotation.getDesc(), annotation.isVisible()); + annotation.accept(visitor); + } + } + } + + public static void retypeVariableAndReceivers(MethodNode methodNode, VarInsnNode targetVarInsn, int newIndex, String newOwner) { + targetVarInsn.var = newIndex; + + Frame[] frames = FrameUtil.getFrames(methodNode); + for (AbstractInsnNode insn : methodNode.instructions) { + // We only care about method invocations that have a receiver + if (insn instanceof MethodInsnNode minsn && minsn.getOpcode() != Opcodes.INVOKESTATIC) { + Frame frame = frames[methodNode.instructions.indexOf(insn)]; + if (frame == null || frame.getStackSize() <= 0) continue; // Dead code + + SourceValue receiver = frame.getStack(0); + // Check if our target is one of the instructions that produced this value + if (receiver.insns.contains(targetVarInsn)) { + minsn.owner = newOwner; + } + } + } + } + + private Parameters() { + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java index ed9f9a56..b211df21 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java @@ -7,8 +7,7 @@ import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.next.env.ann.MixinData; -import org.sinytra.adapter.next.pipeline.config.ConfigurationImpl; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.config.*; import org.sinytra.adapter.next.pipeline.processor.Processor; import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.resolver.Resolver; @@ -16,12 +15,15 @@ import org.sinytra.adapter.next.pipeline.resolver.Resolver.ResultType; import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.type.MixinType; +import org.sinytra.adapter.next.type.MixinTypes; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.Patch; import org.sinytra.adapter.patch.util.MethodQualifier; import org.slf4j.Logger; import java.util.Objects; +import java.util.Set; import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; @@ -29,18 +31,16 @@ public class PipelineExecutor { private static final Logger LOGGER = LogUtils.getLogger(); - private final MixinType mixinType; private final ClassTarget classTarget; private final MixinContext context; - public PipelineExecutor(MixinType mixinType, ClassTarget classTarget, MixinContext context) { - this.mixinType = mixinType; + public PipelineExecutor(ClassTarget classTarget, MixinContext context) { this.classTarget = classTarget; this.context = context; } - public Patch.Result execute() { - MixinData data = parseMixinData(); + public Patch.Result execute(MixinType mixinType) { + MixinData data = parseMixinData(mixinType); if (data == null) { return Patch.Result.PASS; } @@ -48,7 +48,7 @@ public Patch.Result execute() { Resolvers resolvers = new Resolvers(); Processors processors = new Processors(); - PropertyContainerTemplate template = Objects.requireNonNull(this.mixinType.getConfigurationTemplate()); + PropertyContainerTemplate template = Objects.requireNonNull(mixinType.getConfigurationTemplate()); // 1. Create clean config ConfigurationImpl cleanConfig = new ConfigurationImpl(template); @@ -59,14 +59,18 @@ public Patch.Result execute() { cleanConfig.setReturnType(Type.getReturnType(context.methodNode().desc)); // 1.1. Create dirty config - ConfigurationImpl dirtyConfig = new ConfigurationImpl(template, cleanConfig); + MutableConfiguration dirtyConfig = new ConfigurationImpl(template, cleanConfig); dirtyConfig.inheritMixinType(); dirtyConfig.inheritTargetClass(); - Recipe recipe = new Recipe(cleanConfig, dirtyConfig, resolvers, processors); + Recipe recipe = new Recipe(cleanConfig, dirtyConfig, resolvers, processors, this.context); // 2. Complete clean config - this.mixinType.preProcess(data, this.context, cleanConfig, recipe); + TxResult preResult = mixinType.preProcess(data, this.context, cleanConfig, recipe); + if (preResult == TxResult.FAIL) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed preProcess", mixinId); + return Patch.Result.PASS; + } // 2.1. Validate clean config if (!cleanConfig.validate()) { @@ -77,13 +81,15 @@ public Patch.Result execute() { // 3. Run Resolvers resolvers.freeze(); for (Resolver resolver : resolvers.getAll()) { - ResolutionResult res = resolver.resolve(data, this.context, cleanConfig, dirtyConfig, recipe); + ResolutionResult res = resolver.resolve(data, this.context, recipe); Objects.requireNonNull(res, "BUG: Received null from resolver " + resolver.getClass()); - if (res.type() == ResultType.SUCCESS || res.type() == ResultType.FINALIZE) { - dirtyConfig.mergeFrom(res.patch()); - if (res.type() == ResultType.FINALIZE) { + if (res.type() == ResultType.SUCCESS || res.type() == ResultType.REPLACE) { + if (res.type() == ResultType.REPLACE) { + dirtyConfig = res.patch().copy(); break; + } else { + dirtyConfig.mergeFrom(res.patch()); } } else if (res.type() == ResultType.FAIL) { LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed RESOLVER {}", mixinId, resolver.getClass().getSimpleName()); @@ -91,10 +97,18 @@ public Patch.Result execute() { } } - // TODO Check and make sure resolvers don't modify the method/class (maybe with a propert switch to skip these in prod) - // 4. Complete dirty config - this.mixinType.postProcess(data, this.context, cleanConfig, dirtyConfig, recipe); + if (dirtyConfig.hasProperty(Configuration.Keys.MIXIN_TYPE)) { + String type = dirtyConfig.getMixinType(); + MixinType lateMixinType = MixinTypes.getMixinType(Type.getType(type).getInternalName()); + if (lateMixinType != null) { + TxResult postResult = lateMixinType.postProcess(data, this.context, cleanConfig, dirtyConfig, recipe); + if (postResult == TxResult.FAIL) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed postProcess", mixinId); + return Patch.Result.PASS; + } + } + } // 4.1. Validate dirty config if (!dirtyConfig.validate()) { @@ -119,7 +133,7 @@ public Patch.Result execute() { } @Nullable - private MixinData parseMixinData() { + private MixinData parseMixinData(MixinType mixinType) { AnnotationHandle atHandle = this.context.legacy().injectionPointAnnotation(); if (atHandle == null) { return null; @@ -132,6 +146,21 @@ private MixinData parseMixinData() { MethodQualifier targetMethod = this.context.legacy().getTargetMethodQualifier(); AnnotationHandle methodHandle = this.context.legacy().methodAnnotation(); - return this.mixinType.parse(this.context, this.classTarget, targetMethod, atData, methodHandle); + + Set> keys = mixinType.requestProperties(); + BasePropertyContainer properties = new BasePropertyContainer(); + for (PropertyKey key : keys) { + Object value = methodHandle.getValue(key.name()).map(AnnotationValueHandle::get).orElse(null); + if (value == null) continue; + + if (key.parser() != null) { + Object parsed = key.parser().parse(value, this.context); + properties.setProperty(key, parsed); + } else { + throw new IllegalStateException("Cannot parse for key %s, it does not define a parser".formatted(key.name())); + } + } + + return new MixinData(this.classTarget, targetMethod, atData, properties); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java index d7f66512..345cc051 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java @@ -1,15 +1,29 @@ package org.sinytra.adapter.next.pipeline; +import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.resolver.Resolvers; +import org.sinytra.adapter.patch.api.MethodContext; /** * Defines the initial and desired states, which include mixin method metadata and per-mixin-type variables. - * + * * @param clean original state before patching * @param dirty desired state necessary to fix the mixin */ -public record Recipe(Configuration clean, MutableConfiguration dirty, Resolvers resolvers, Processors processors) { +public record Recipe(Configuration clean, Configuration dirty, Resolvers resolvers, Processors processors, MixinContext context) { + public Recipe withDirtyConfig(Configuration dirty) { + return new Recipe(this.clean, dirty, this.resolvers, this.processors, this.context); + } + + public MethodContext.TargetPair getCleanTarget() { + if (clean.getTargetMethod() == null) return null; + return context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); + } + + public MethodContext.TargetPair getDirtyTarget() { + if (dirty.getTargetMethod() == null) return null; + return context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java index d52e3311..7a8eab6c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java @@ -54,6 +54,12 @@ public MutablePropertyContainer setProperty(PropertyKey key, @Nullable T return this; } + @Override + public MutablePropertyContainer removeProperty(PropertyKey key) { + this.properties.remove(key); + return this; + } + @Override public Map, Object> getProperties() { return ImmutableMap.copyOf(this.properties); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java index 1306fb15..3283a30e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java @@ -1,11 +1,17 @@ package org.sinytra.adapter.next.pipeline.config; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.MethodInsnNode; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.ann.ConstantData; import org.sinytra.adapter.next.env.ann.SliceData; import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.MethodQualifier; +import java.util.List; + public interface Configuration extends PropertyContainer { String getMixinType(); @@ -23,25 +29,47 @@ public interface Configuration extends PropertyContainer { MutableConfiguration subConfig(); + MutableConfiguration subConfig(PropertyContainerTemplate template); + MutableConfiguration copy(); final class Keys { // Mixin meta - public static final PropertyKey MIXIN_TYPE = new PropertyKey<>("mixin_type"); - public static final PropertyKey TARGET_CLASS = new PropertyKey<>("target_class"); - public static final PropertyKey TARGET_METHOD = new PropertyKey<>("target_method"); - public static final PropertyKey TARGET_AT = new PropertyKey<>("target_at"); + public static final PropertyKey MIXIN_TYPE = PropertyKey.create("mixin_type"); + public static final PropertyKey TARGET_CLASS = PropertyKey.create("target_class"); + public static final PropertyKey TARGET_METHOD = PropertyKey.create("target_method"); + public static final PropertyKey TARGET_AT = PropertyKey.create("target_at"); + public static final PropertyKey TARGET_CONSTANT = PropertyKey.create("target_constant"); // Method - public static final PropertyKey PARAMETERS = new PropertyKey<>("parameters"); - public static final PropertyKey RETURN_TYPE = new PropertyKey<>("return_type"); + public static final PropertyKey PARAMETERS = PropertyKey.create("parameters"); + public static final PropertyKey RETURN_TYPE = PropertyKey.create("return_type"); // Control - public static final PropertyKey DELETE = new PropertyKey<>("delete"); - // Misc - public static final PropertyKey ORDINAL = new PropertyKey<>("ordinal"); - public static final PropertyKey INDEX = new PropertyKey<>("index"); - public static final PropertyKey SLICE = new PropertyKey<>("slice"); + public static final PropertyKey DELETE = PropertyKey.create("delete"); + + // Mixin data + public static final PropertyKey CANCELLABLE = PropertyKey.create("cancellable", Boolean.class); + public static final PropertyKey INDEX = PropertyKey.create("index", Integer.class); + public static final PropertyKey ORDINAL = PropertyKey.create("ordinal", Integer.class); + public static final PropertyKey ARGS_ONLY = PropertyKey.create("argsOnly", Boolean.class); + public static final PropertyKey SLICE = PropertyKey.builder("slice") + .parser((value, mapper) -> SliceData.parse(new AnnotationHandle((AnnotationNode) value), mapper)) + .build(); + public static final PropertyKey> SLICES = PropertyKey.>builder("slice") + .parser((value, mapper) -> ((List) value).stream() + .map(AnnotationHandle::new) + .map(n -> SliceData.parse(n, mapper)) + .toList()) + .build(); private Keys() { } } + + final class SpecialKeys { + // Hidden + public static final PropertyKey EXTRACT_TARGET = PropertyKey.create("_extract_target_minsn"); + + private SpecialKeys() { + } + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java index dd28b4fd..0070494b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java @@ -5,6 +5,7 @@ import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.param.Copiable; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -33,6 +34,11 @@ public MutableConfiguration setProperty(PropertyKey key, @Nullable T valu return (MutableConfiguration) super.setProperty(key, value); } + @Override + public MutableConfiguration removeProperty(PropertyKey key) { + return (MutableConfiguration) super.removeProperty(key); + } + @Override public MutableConfiguration inheritMixinType() { return inheritProperty(Keys.MIXIN_TYPE); @@ -105,8 +111,9 @@ public boolean shouldDelete() { } @Override - public void setTargetClass(String targetClass) { + public MutableConfiguration setTargetClass(String targetClass) { setProperty(Keys.TARGET_CLASS, targetClass); + return this; } @Override @@ -170,7 +177,10 @@ public void inheritProperyIfAbsent(PropertyKey key) { @SuppressWarnings({"unchecked", "rawtypes"}) private ConfigurationImpl inheritProperty(PropertyKey key) { if (this.parent != null) { - this.parent.getProperty(key).ifPresent(o -> setProperty((PropertyKey) key, o)); + this.parent.getProperty(key).ifPresent(o -> { + Object entry = o instanceof Copiable c ? c.copy() : o; + setProperty((PropertyKey) key, entry); + }); } return this; } @@ -185,6 +195,11 @@ public MutableConfiguration subConfig() { return new ConfigurationImpl(this.template, this.parent); } + @Override + public MutableConfiguration subConfig(PropertyContainerTemplate template) { + return new ConfigurationImpl(template, this.parent); + } + @Override protected MutablePropertyContainer createCopyImpl() { return subConfig(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java index fdc436b5..43341b7f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.ann.AtData; @@ -10,7 +11,11 @@ public interface MutableConfiguration extends Configuration, MutablePropertyContainer { static MutableConfiguration create() { - return new ConfigurationImpl(); + return create(null); + } + + static MutableConfiguration create(@Nullable PropertyContainerTemplate template) { + return new ConfigurationImpl(template); } MutableConfiguration inheritMixinType(); @@ -18,8 +23,12 @@ static MutableConfiguration create() { MutableConfiguration setMixinType(String mixinType); MutableConfiguration inheritTargetClass(); + + default MutableConfiguration setTargetClass(ClassNode targetClass) { + return setTargetClass(targetClass.name); + } - void setTargetClass(String targetClass); + MutableConfiguration setTargetClass(String targetClass); MutableConfiguration inheritTargetMethod(); @@ -47,5 +56,7 @@ static MutableConfiguration create() { MutableConfiguration setProperty(PropertyKey key, @Nullable T value); + MutableConfiguration removeProperty(PropertyKey key); + void inheritProperyIfAbsent(PropertyKey key); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java index f83f2ccf..66565786 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java @@ -4,6 +4,7 @@ public interface MutablePropertyContainer extends PropertyContainer { MutablePropertyContainer setProperty(PropertyKey key, @Nullable T value); + MutablePropertyContainer removeProperty(PropertyKey key); MutablePropertyContainer mergeFrom(PropertyContainer other); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java index 3cbf189a..81b21a11 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java @@ -1,5 +1,7 @@ package org.sinytra.adapter.next.pipeline.config; +import com.google.common.collect.ImmutableList; + import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; @@ -7,8 +9,8 @@ public class PropertyContainerTemplate { private final List constraints; - public PropertyContainerTemplate(List constraints) { - this.constraints = constraints; + private PropertyContainerTemplate(List constraints) { + this.constraints = ImmutableList.copyOf(constraints); } public boolean validate(PropertyContainer container) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java index 35fbeb29..657fab9b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java @@ -1,6 +1,8 @@ package org.sinytra.adapter.next.pipeline.config; +import com.google.common.base.MoreObjects; import org.jetbrains.annotations.Nullable; +import org.sinytra.adapter.next.env.ctx.RefMapper; import java.util.Objects; import java.util.function.Predicate; @@ -8,14 +10,12 @@ public class PropertyKey { private final String name; private final Predicate predicate; + private final Parser parser; - public PropertyKey(String name) { - this(name, null); - } - - public PropertyKey(String name, @Nullable Predicate predicate) { + public PropertyKey(String name, @Nullable Predicate predicate, @Nullable Parser parser) { this.name = Objects.requireNonNull(name); this.predicate = Objects.requireNonNullElseGet(predicate, () -> x -> true); + this.parser = parser; } public boolean validate(T value) { @@ -25,4 +25,59 @@ public boolean validate(T value) { public String name() { return this.name; } + + public Parser parser() { + return this.parser; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("name", name) + .toString(); + } + + public static PropertyKey create(String name) { + return new PropertyKey<>(name, null, null); + } + + public static PropertyKey create(String name, Class type) { + return PropertyKey.builder(name).parseAs(type).build(); + } + + public static Builder builder(String name) { + return new Builder<>(name); + } + + public interface Parser { + T parse(Object value, RefMapper mapper); + } + + public static class Builder { + private final String name; + private Predicate predicate; + private Parser parser; + + public Builder(String name) { + this.name = name; + } + + public Builder predicate(Predicate predicate) { + this.predicate = predicate; + return this; + } + + public Builder parseAs(Class type) { + return parser((value, context) -> type.cast(value)); + } + + public Builder parser(Parser parser) { + this.parser = parser; + return this; + } + + public PropertyKey build() { + return new PropertyKey<>(this.name, this.predicate, this.parser); + } + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java index 519cf3f1..f62519ae 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java @@ -1,19 +1,38 @@ package org.sinytra.adapter.next.pipeline.processor; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.ConstantData; +import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.api.MixinConstants; public class InjectionTargetProcessor implements Processor { @Override public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { - if (dirty.getAtData() == null) return TxResult.FAIL; + if (!dirty.hasProperty(Keys.TARGET_AT) && !dirty.hasProperty(Keys.TARGET_CONSTANT)) { + return TxResult.PASS; + } - AnnotationHandle handle = context.injectionPointAnnotation(); - dirty.getAtData().apply(handle); + AnnotationHandle annotation = context.methodAnnotation(); + if (dirty.getAtData() != null) { + AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_AT, MixinConstants.AT); + dirty.getAtData().apply(handle); + } else { + annotation.removeValues(MixinAnnotationConstants.PROPERTY_AT); + } + + if (dirty.hasProperty(Keys.TARGET_CONSTANT)) { + AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_CONSTANT, MixinConstants.CONSTANT); + ConstantData cst = dirty.getProperty(Keys.TARGET_CONSTANT).orElseThrow(); + cst.apply(handle); + } else { + annotation.removeValues(MixinAnnotationConstants.PROPERTY_CONSTANT); + } return TxResult.SUCCESS; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java index 994cb378..9492821e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java @@ -12,16 +12,11 @@ public class ParameterUsageProcessor implements Processor { @Override public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { -// Configuration clean = recipe.clean(); String cleanTarget = recipe.clean().getAtData().getTarget().orElse(null); if (cleanTarget == null) return TxResult.PASS; String dirtyTarget = dirty.getAtData().getTarget().orElse(null); if (dirtyTarget == null) return TxResult.PASS; -// if (cleanTarget.equals(dirtyTarget) || !clean.getParameters().has(ParamGroup.METHOD_PARAMS) -// || !dirty.getParameters().has(ParamGroup.METHOD_PARAMS) -// ) return TxResult.PASS; - MethodQualifier cleanTargetQual = MethodQualifier.create(cleanTarget).orElseThrow(); MethodQualifier dirtyTargetQual = MethodQualifier.create(dirtyTarget).orElseThrow(); for (AbstractInsnNode insn : context.methodNode().instructions) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java index b1f918a8..e1501d56 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java @@ -1,8 +1,12 @@ package org.sinytra.adapter.next.pipeline.processor; +import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.VarInsnNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; @@ -12,22 +16,52 @@ import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformTarget; import java.util.List; +import java.util.Map; +import java.util.Set; public class ParametersProcessor implements Processor { @Override public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { - if (dirty.getParameters() == null) return TxResult.FAIL; + MethodParameters cleanParams = recipe.clean().getParameters(); + MethodParameters dirtyParams = dirty.getParameters(); + if (dirtyParams == null) return TxResult.FAIL; - List cleanParams = recipe.clean().getParameters().merge(); - List dirtyParams = dirty.getParameters().merge(); - ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(cleanParams, dirtyParams); + // Apply mappings of params that will be removed in dirty + Map> oldVarMap = Parameters.gatherVarMappings(context.methodNode(), cleanParams.merge(), dirtyParams.merge(), dirtyParams.getMapping()); + if (cleanParams.getOrder().equals(dirtyParams.getOrder())) { + List order = dirtyParams.getOrder(); + int offset = 0; + for (MethodParameters.ParamGroup group : order) { + List cleanList = cleanParams.getTypes(group); + List dirtyList = dirtyParams.getTypes(group); + + if (!applyDiff(cleanList, dirtyList, context, offset)) { + return TxResult.FAIL; + } + offset += dirtyList.size(); + } + } else { + if (!applyDiff(cleanParams.mergeTypes(), dirtyParams.mergeTypes(), context, 0)) { + return TxResult.FAIL; + } + } + + // Apply mappings of params that only exist in dirty + Parameters.applyVarMappings(context.methodNode(), Parameters.gatherVarMappings(context.methodNode(), dirtyParams.merge(), dirtyParams.merge(), dirtyParams.getMapping())); + Parameters.applyVarMappings(context.methodNode(), oldVarMap); + Parameters.applyAnnotations(context.methodNode(), dirtyParams.merge()); + + return TxResult.SUCCESS; + } + + private boolean applyDiff(List clean, List dirty, MixinContext context, int offset) { + ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(clean, dirty); if (!diff.isEmpty()) { - Patch.Result result = diff.asParameterTransformer(ParamTransformTarget.ALL, false) + Patch.Result result = diff.offset(offset).asParameterTransformer(ParamTransformTarget.ALL, false, Set.of()) .apply(context.legacy()); - return result == Patch.Result.PASS ? TxResult.FAIL : TxResult.SUCCESS; + return result != Patch.Result.PASS; } - - return TxResult.PASS; + return true; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java index e9bd1caf..58f3da1f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java @@ -1,6 +1,7 @@ package org.sinytra.adapter.next.pipeline.processor; import org.sinytra.adapter.next.env.OrderedRegistry; +import org.sinytra.adapter.next.pipeline.processor.extract.ExtractMixinProcessor; public class Processors extends OrderedRegistry { @@ -10,6 +11,7 @@ public Processors() { private void registerDefaultProcessors() { add(new DisableMixinProcessor()); + add(new ExtractMixinProcessor()); add(new MixinTypeProcessor()); add(new TargetMethodProcessor()); add(new InjectionTargetProcessor()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java index 3f1527c3..f51fbe9a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java @@ -11,8 +11,9 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.ArrayList; import java.util.List; @@ -32,7 +33,7 @@ public TxResult process(MixinData mixin, MixinContext context, Configuration dir return TxResult.PASS; } - ReturnInterpreter inter = MethodCallAnalyzer.analyzeInterpretMethod(context.methodNode(), new ReturnInterpreter()); + ReturnInterpreter inter = MethodAnalyzer.analyzeInterpretMethod(context.methodNode(), new ReturnInterpreter()); for (AbstractInsnNode insn : inter.insns) { if (insn.getOpcode() != Opcodes.ACONST_NULL) { adapter.apply(context.methodNode().instructions, insn); @@ -54,10 +55,11 @@ public ReturnInterpreter() { @Override public void returnOperation(AbstractInsnNode insn, SourceValue value, SourceValue expected) { - if (value.getSize() != 1) { + AbstractInsnNode srcInsn = AdapterUtil.getSingleInsn(value); + if (srcInsn == null) { throw new IllegalStateException(); } - this.insns.add(value.insns.iterator().next()); + this.insns.add(srcInsn); } } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java index 6019dd4f..4cef3955 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java @@ -1,10 +1,14 @@ package org.sinytra.adapter.next.pipeline.processor; +import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.List; @@ -18,6 +22,25 @@ public TxResult process(MixinData mixin, MixinContext context, Configuration dir context.methodAnnotation() .setOrAppendNonNull(AT_METHOD, List.of(dirty.getTargetMethod().asDescriptor())); + upgradeCapturedLocals(context.methodNode(), context.legacy()); + return TxResult.SUCCESS; } + + // TODO Is there a better approach? + private static void upgradeCapturedLocals(MethodNode methodNode, MethodContext methodContext) { + AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(methodNode, methodContext); + if (capturedLocals == null) { + return; + } + + List availableLocals = methodContext.getTargetMethodLocals(capturedLocals.target()); + // For now, only handle cases where all locals are part of the method's params, convenient when switching the target to a lambda + if (availableLocals == null || !availableLocals.isEmpty()) { + return; + } + + LocalVarAnalyzer.CapturedLocalsTransform transform = LocalVarAnalyzer.analyzeCapturedLocals(capturedLocals, methodNode); + transform.remover().apply(methodContext); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java new file mode 100644 index 00000000..dde71a01 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java @@ -0,0 +1,29 @@ +package org.sinytra.adapter.next.pipeline.processor.extract; + +import org.objectweb.asm.tree.MethodInsnNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.processor.Processor; +import org.sinytra.adapter.patch.api.Patch; +import org.sinytra.adapter.patch.transformer.operation.unit.ExtractMixin; + +public class ExtractMixinProcessor implements Processor { + @Override + public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + if (recipe.clean().getTargetClass().equals(dirty.getTargetClass())) return TxResult.PASS; + + Patch.Result result = new ExtractMixin(dirty.getTargetClass()).apply(context.legacy()); + if (result == Patch.Result.PASS && dirty.hasProperty(Configuration.SpecialKeys.EXTRACT_TARGET)) { + MethodInsnNode minsn = dirty.getProperty(Configuration.SpecialKeys.EXTRACT_TARGET).orElseThrow(); + result = new MirrorableExtractMixin(dirty.getTargetClass(), minsn).apply(context.legacy()); + } + if (result == Patch.Result.PASS) { + return TxResult.FAIL; + } + + return TxResult.SUCCESS; + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/MirrorableExtractMixin.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java similarity index 84% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/MirrorableExtractMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java index f9db46b9..f313085e 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/MirrorableExtractMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.dynfix; +package org.sinytra.adapter.next.pipeline.processor.extract; import com.google.common.collect.ImmutableList; import org.objectweb.asm.Opcodes; @@ -6,10 +6,11 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.patch.api.*; -import org.sinytra.adapter.patch.transformer.operation.CompoundMethodTransform; +import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionTarget; import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.OpcodeUtil; import java.util.ArrayList; @@ -33,7 +34,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont return Patch.Result.PASS; } - List callInsns = MethodCallAnalyzer.findMethodCallParamInsns(methodContext.findDirtyInjectionTarget().methodNode(), this.destinationMethodInvocation); + List callInsns = MethodCallAnalyzer.getMethodCallSrcInsns(methodContext.findDirtyInjectionTarget().methodNode(), this.destinationMethodInvocation); if (callInsns == null || callInsns.size() <= selfIndex) { return Patch.Result.PASS; } @@ -48,7 +49,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont MethodNode originalMixinMethod = methodContext.getMixinMethod(); String name = originalMixinMethod.name + "$adapter$mirror$" + AdapterUtil.randomString(5); List originalParams = List.of(Type.getArgumentTypes(originalMixinMethod.desc)); - List newParams = ImmutableList.builder().add(Type.getArgumentTypes(this.destinationMethodInvocation.desc)).add(AdapterUtil.CI_TYPE).build(); + List newParams = ImmutableList.builder().add(Type.getArgumentTypes(this.destinationMethodInvocation.desc)).add(MixinConstants.CI_TYPE).build(); // Make sure we have all required params if (!new HashSet<>(newParams).containsAll(originalParams)) { return Patch.Result.PASS; @@ -56,9 +57,11 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont String desc = Type.getMethodDescriptor(Type.VOID_TYPE, newParams.toArray(Type[]::new)); // Change target - CompoundMethodTransform.builder(b -> b - .modifyTarget(this.destinationMethodInvocation.name + this.destinationMethodInvocation.desc)) - .apply(methodContext); + Patch.Result result = new ModifyInjectionTarget(List.of(MethodQualifier.create(destinationMethodInvocation).asDescriptor())).apply(methodContext); + if (result == Patch.Result.PASS) { + return Patch.Result.PASS; + } + MethodNode invokerMixinMethod = (MethodNode) generatedTarget.visitMethod(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, name, desc, null, null); invokerMixinMethod.visibleAnnotations = new ArrayList<>(originalMixinMethod.visibleAnnotations); // Make original mixin a unique public method diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java new file mode 100644 index 00000000..6581204b --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java @@ -0,0 +1,95 @@ +package org.sinytra.adapter.next.pipeline.processor.wrapop; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.SourceValue; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.selector.FrameUtil; +import org.sinytra.adapter.patch.util.AdapterUtil; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WrapOpAnalyzer { + public static List> groupArrayInitializers(MethodNode methodNode, AbstractInsnNode newArrayInsn) { + // 1. Analyze the method frames to track data flow + Frame[] frames = FrameUtil.getFrames(methodNode); + + // Map to hold the AASTORE instruction for each array index + // Key = Array Index (0, 1...), Value = The AASTORE instruction node + Map indexToStoreNode = new HashMap<>(); + + // 2. Scan for AASTORE instructions targeting our array + InsnList instructions = methodNode.instructions; + for (int i = 0; i < instructions.size(); i++) { + AbstractInsnNode insn = instructions.get(i); + + if (insn.getOpcode() == Opcodes.AASTORE) { + Frame frame = frames[i]; + + // Stack for AASTORE: [..., arrayRef, dup, index, value] + // arrayRef is at stack size - 4 + SourceValue arrayRefSource = frame.getStack(frame.getStackSize() - 4); + + // Check if this AASTORE is operating on the array created by newArrayInsn + if (arrayRefSource.insns.contains(newArrayInsn)) { + // Get the index (stack size - 2) + SourceValue indexSource = frame.getStack(frame.getStackSize() - 2); + Integer constantIndex = resolveConstantIndex(indexSource); + + if (constantIndex != null) { + indexToStoreNode.put(constantIndex, insn); + } + } + } + } + + // 3. Group the instructions linearly + // We assume the compiler emits instructions in contiguous blocks for each element. + List> groups = new ArrayList<>(); + + // Start looking after the creation of the array + AbstractInsnNode currentStart = newArrayInsn.getNext(); + + // Find the maximum index we encountered to size our list + int maxIndex = indexToStoreNode.keySet().stream().max(Integer::compare).orElse(-1); + + for (int i = 0; i <= maxIndex; i++) { + AbstractInsnNode endNode = indexToStoreNode.get(i); + + List currentGroup = new ArrayList<>(); + + if (endNode != null) { + // Collect everything from currentStart up to (and including) the AASTORE + AbstractInsnNode ptr = currentStart; + while (ptr != null) { + currentGroup.add(ptr); + if (ptr == endNode) break; + ptr = ptr.getNext(); + } + // Advance start pointer for the next group + currentStart = endNode.getNext(); + } + + groups.add(currentGroup); + } + + return groups; + } + + // Helper to extract the integer value from a SourceValue + private static Integer resolveConstantIndex(SourceValue source) { + for (AbstractInsnNode insn : source.insns) { + int index = AdapterUtil.getIntConstValue(insn).orElse(-1); + if (index != -1) { + return index; + } + } + return null; // Could not resolve to a static constant + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java new file mode 100644 index 00000000..29f76757 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java @@ -0,0 +1,173 @@ +package org.sinytra.adapter.next.pipeline.processor.wrapop; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameter; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.processor.Processor; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.MethodQualifier; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class WrapOpParamsProcessor implements Processor { + private static final MethodQualifier WO_ORIGINAL_CALL = new MethodQualifier("Lcom/llamalad7/mixinextras/injector/wrapoperation/Operation;", "call", "([Ljava/lang/Object;)Ljava/lang/Object;"); + + @Override + public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + if (dirty.getParameters() == null) return TxResult.FAIL; + + // Find original.call(...) + List> cleanCalls = MethodCallAnalyzer.getAllMethodCallSrcInsnsInclusive(context.unmodifiedMethodNode(), WO_ORIGINAL_CALL); + List> dirtyCalls = MethodCallAnalyzer.getAllMethodCallSrcInsnsInclusive(context.methodNode(), WO_ORIGINAL_CALL); + if (cleanCalls.size() != dirtyCalls.size()) { + return TxResult.FAIL; + } + + for (int i = 0; i < dirtyCalls.size(); i++) { + List cleanCall = cleanCalls.get(i); + List dirtyCall = dirtyCalls.get(i); + if (!upgradeOriginalCall(context, dirty, cleanCall, dirtyCall)) { + return TxResult.FAIL; + } + } + + // Upgrade calls on "instance" variable + AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(recipe.getCleanTarget()); + AbstractInsnNode dirtyInsn = context.methods().findInjectionTargetInsn(recipe.getDirtyTarget()); + if (cleanInsn instanceof MethodInsnNode cleanMinsn && dirtyInsn instanceof MethodInsnNode dirtyMinsn) { + List methodParams = dirty.getParameters().getTypes(MethodParameters.ParamGroup.METHOD_PARAMS); + boolean result = WrapOpSurgeon.tryUpgrade(context, recipe, methodParams, cleanMinsn, dirtyMinsn); + if (!result) { + return TxResult.FAIL; + } + } + + return TxResult.PASS; + } + + @Nullable + private static WrapOpOriginalCall parseOriginalCall(MethodNode methodNode, List callInsns) { + if (callInsns.size() < 2) { + return null; + } + AbstractInsnNode singleArg = callInsns.get(1); + if (!(singleArg instanceof TypeInsnNode tinsn) || tinsn.getOpcode() != Opcodes.ANEWARRAY) { + return null; + } + List> arrayInitArgs = WrapOpAnalyzer.groupArrayInitializers(methodNode, singleArg); + return WrapOpOriginalCall.parse(arrayInitArgs); + } + + private static boolean upgradeOriginalCall(MixinContext context, Configuration dirty, List cleanCallInsns, List dirtyCallInsns) { + WrapOpOriginalCall cleanCall = parseOriginalCall(context.unmodifiedMethodNode(), cleanCallInsns); + if (cleanCall == null) return false; + + WrapOpOriginalCall dirtyCall = parseOriginalCall(context.methodNode(), dirtyCallInsns); + if (dirtyCall == null) return false; + + AbstractInsnNode arrayInit = dirtyCallInsns.get(1); + List params = dirty.getParameters().get(MethodParameters.ParamGroup.METHOD_PARAMS); + + LocalVariableLookup lookup = new LocalVariableLookup(context.methodNode()); + List args = IntStream.range(0, params.size()) + .mapToObj(i -> { + Parameter param = params.get(i); + int index = lookup.getByParameterOrdinal(i).index; + return WrapOpOriginalCall.CallArg.create(i, List.of(AdapterUtil.loadType(param.getType(), index))); + }) + .toList(); + WrapOpOriginalCall reconstruct = new WrapOpOriginalCall(args); + + AbstractInsnNode start = arrayInit.getNext(); // After ANEWARRAY + AbstractInsnNode dirtyInvoke = dirtyCallInsns.getLast(); + if (!(dirtyInvoke instanceof MethodInsnNode)) return false; + AbstractInsnNode end = dirtyInvoke.getPrevious(); // Before INVOKEVIRTUAL call() + + InsnList methodInsns = context.methodNode().instructions; + AdapterUtil.replaceRangeInclusive(methodInsns, start, end, reconstruct.merge()); + + // Change array size + if (AdapterUtil.getIntConstValue(arrayInit.getPrevious()).isPresent()) { + methodInsns.set(arrayInit.getPrevious(), AdapterUtil.getIntConstInsn(args.size())); + } else { + InsnList loadNewSize = AdapterUtil.insnsWithAdapter(c -> { + c.pop(); + c.iconst(args.size()); + }); + methodInsns.insertBefore(arrayInit, loadNewSize); + } + + return true; + } + + public record WrapOpOriginalCall(List args) { + public record CallArg(List pre, List load, List post) { + public static CallArg create(int index, List load) { + List pre = List.of( + new InsnNode(Opcodes.DUP), + AdapterUtil.getIntConstInsn(index) + ); + List post = List.of( + new InsnNode(Opcodes.AASTORE) + ); + return new WrapOpOriginalCall.CallArg(pre, load, post); + } + + @Nullable + public static CallArg parse(List insns) { + if (insns.size() < 4 || insns.getFirst().getOpcode() != Opcodes.DUP) + return null; + AbstractInsnNode idxInsn = insns.get(1); + if (AdapterUtil.getIntConstValue(idxInsn).isEmpty()) + return null; + + AbstractInsnNode aastore = insns.getLast(); + if (aastore.getOpcode() != Opcodes.AASTORE) + return null; + + return new CallArg( + insns.subList(0, 2), + insns.subList(2, insns.size() - 1), + List.of(insns.getLast()) + ); + } + } + + public List merge() { + return this.args.stream() + .flatMap(a -> Stream.of(a.pre, a.load, a.post).flatMap(Collection::stream)) + .toList(); + } + + @Nullable + public static WrapOpOriginalCall parse(List> argsInsns) { + if (argsInsns.isEmpty()) + return null; + + List args = new ArrayList<>(); + for (List insns : argsInsns) { + CallArg arg = CallArg.parse(insns); + if (arg == null) { + return null; + } + args.add(arg); + } + + return new WrapOpOriginalCall(args); + } + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java new file mode 100644 index 00000000..7b447125 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java @@ -0,0 +1,146 @@ +package org.sinytra.adapter.next.pipeline.processor.wrapop; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.datafixers.util.Pair; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; +import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil; +import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.OpcodeUtil; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.IntStream; + +public class WrapOpSurgeon { + + public static boolean tryUpgrade(MixinContext context, Recipe recipe, List methodParams, MethodInsnNode cleanInsn, MethodInsnNode dirtyInsn) { + MethodNode methodNode = context.methodNode(); + LocalVariableLookup mixinLocals = new LocalVariableLookup(methodNode); + + Multimap usedVars = getUsedVars(mixinLocals, methodParams, context); + Map>> adapters = new HashMap<>(); + + for (Integer key : usedVars.keys()) { + if (key == 0) { + Pair> pair = findReplacementForInstance(cleanInsn, dirtyInsn, context, recipe); + if (pair != null) { + adapters.put(key, pair); + continue; + } + } + return false; + } + + usedVars.forEach((i, insn) -> { + Pair> adapter = adapters.get(i); + adapter.getFirst().apply(methodNode.instructions, insn); + }); + + for (Pair> pair : adapters.values()) { + if (pair.getSecond() != null) { + pair.getSecond().accept(methodNode.instructions); + } + } + + return true; + } + + @Nullable + private static Pair> findReplacementForInstance(MethodInsnNode cleanInsn, MethodInsnNode dirtyInsn, MixinContext context, Recipe recipe) { + MethodNode cleanTargetMethod = recipe.getCleanTarget().methodNode(); + List receiverInsns = MethodCallAnalyzer.getMethodCallArgInsns(cleanTargetMethod, cleanInsn).getFirst(); + if (!receiverInsns.isEmpty() && receiverInsns.getFirst() instanceof VarInsnNode varInsn) { + BytecodeFixerUpper bfu = context.patchContext().environment().bytecodeFixerUpper(); + if (bfu == null) { + return null; + } + + LocalVariableLookup cleanLookup = context.legacy().cleanLocalsTable(); + LocalVariableNode lvn = cleanLookup.getByIndex(varInsn.var); + + TypeAdapter typeAdapter = bfu.getTypeAdapter(Type.getObjectType(dirtyInsn.owner), Type.getType(lvn.desc)); + if (typeAdapter == null) { + return null; + } + + List subList = receiverInsns.subList(1, receiverInsns.size()); + + TypeAdapter adapter = typeAdapter.andThen((list, insn) -> { + // Fix receiver type originally changed by ReplaceParametersTransformer + for (AbstractInsnNode next = insn.getNext(); next != null && !(next instanceof LabelNode); next = next.getNext()) { + if (next instanceof MethodInsnNode minsn && minsn.owner.equals(dirtyInsn.owner)) { + List args = MethodCallAnalyzer.getMethodCallInsns(context.methodNode(), minsn); + if (args.contains(insn)) { + minsn.owner = cleanInsn.owner; + } + } + } + + list.insert(insn, AdapterUtil.insnList(AdapterUtil.cloneInsns(subList))); + }); + Consumer castCheck = subList.getFirst() instanceof TypeInsnNode typeInsn && typeInsn.getOpcode() == Opcodes.CHECKCAST ? + list -> { + List originalWOCall = new ArrayList<>(ParamTransformationUtil.findWrapOperationOriginalCallArgs(context.methodNode(), context)); + // Include final method call and cast + originalWOCall.add(originalWOCall.getLast().getNext()); + originalWOCall.add(originalWOCall.getLast().getNext()); + originalWOCall.add(originalWOCall.getLast().getNext()); + List cloned = AdapterUtil.cloneInsns(originalWOCall); + + boolean hasLabel = list.getFirst() instanceof LabelNode; + LabelNode label = hasLabel ? (LabelNode) list.getFirst() : new LabelNode(); + InsnList check = AdapterUtil.insnList( + new LabelNode(), + new VarInsnNode(Opcodes.ALOAD, 0), + new TypeInsnNode(Opcodes.INSTANCEOF, typeInsn.desc), + new JumpInsnNode(Opcodes.IFNE, label), + new LabelNode() + ); + typeAdapter.apply(check, check.get(1)); + check.add(AdapterUtil.insnList(cloned)); + check.add(new InsnNode(OpcodeUtil.getReturnOpcode(context.methodNode()))); + if (!hasLabel) { + check.add(label); + } + + list.insert(check); + } + : null; + + return Pair.of(adapter, castCheck); + } + return null; + } + + public static Multimap getUsedVars(LocalVariableLookup mixinLocals, List methodParams, MixinContext context) { + MethodNode methodNode = context.methodNode(); + + List paramVars = IntStream.range(0, methodParams.size()) + .mapToObj(mixinLocals::getByParameterOrdinal) + .map(l -> l.index) + .toList(); + + List originalOpCall = ParamTransformationUtil.findWrapOperationOriginalCallArgs(methodNode, context); + Multimap usedVars = HashMultimap.create(); + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof VarInsnNode varInsn && !originalOpCall.contains(insn) && paramVars.contains(varInsn.var)) { + usedVars.put(varInsn.var, varInsn); + } + } + + return usedVars; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java index da43790a..5e43de12 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java @@ -12,42 +12,47 @@ public abstract class CompoundResolver implements Resolver { protected final List subResolvers = new ArrayList<>(); + public CompoundResolver addSubResolverFirst(SubResolver subResolver) { + this.subResolvers.addFirst(subResolver); + return this; + } + public CompoundResolver addSubResolver(SubResolver subResolver) { this.subResolvers.add(subResolver); return this; } - protected abstract boolean canApply(MixinData mixin, Configuration clean, Configuration dirty); + protected abstract boolean canApply(MixinData mixin, Recipe recipe); @Nullable - protected Configuration tryReuse(MixinContext context, Configuration clean, Configuration dirty) { + protected Configuration tryReuse(MixinContext context, Recipe recipe) { return null; } @Nullable - protected Configuration useFallback(MixinContext context, Configuration clean, Configuration dirty) { + protected Configuration useFallback(MixinContext context, Recipe recipe) { return null; } @Override - public ResolutionResult resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { - if (!canApply(mixin, clean, dirty)) { + public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe) { + if (!canApply(mixin, recipe)) { return ResolutionResult.pass(); } - Configuration resused = tryReuse(context, clean, dirty); + Configuration resused = tryReuse(context, recipe); if (resused != null) { return ResolutionResult.success(resused); } for (SubResolver subResolver : this.subResolvers) { - Configuration result = subResolver.resolve(mixin, context, clean, dirty, recipe); + Configuration result = subResolver.resolve(mixin, context, recipe); if (result != null) { return ResolutionResult.success(result); } } - Configuration fallback = useFallback(context, clean, dirty); + Configuration fallback = useFallback(context, recipe); if (fallback != null) { return ResolutionResult.success(fallback); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java index dec02d08..26eabef4 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java @@ -11,7 +11,7 @@ public interface Resolver { enum ResultType { - FINALIZE, + REPLACE, SUCCESS, PASS, FAIL @@ -30,8 +30,8 @@ public static ResolutionResult success(Configuration patch) { return new ResolutionResult(ResultType.SUCCESS, patch); } - public static ResolutionResult finalize(Configuration patch) { - return new ResolutionResult(ResultType.FINALIZE, patch); + public static ResolutionResult replace(Configuration patch) { + return new ResolutionResult(ResultType.REPLACE, patch); } public Optional maybePatch() { @@ -40,5 +40,5 @@ public Optional maybePatch() { } @NotNull - ResolutionResult resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe); + ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java index 9e1c2fbd..d52fabda 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java @@ -8,5 +8,5 @@ public interface SubResolver { @Nullable - Configuration resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe); + Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java index 51ca7536..8f9ad742 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java @@ -12,7 +12,7 @@ import org.sinytra.adapter.next.pipeline.resolver.SubResolver; import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; import org.sinytra.adapter.patch.util.AdapterUtil; @@ -28,10 +28,10 @@ public class ArbitraryInjectionPointSubResolver implements SubResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { - String injectionPointTarget = clean.getAtData().getTarget().orElseThrow(); - MethodContext.TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); - MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + String injectionPointTarget = recipe.clean().getAtData().getTarget().orElseThrow(); + MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanTarget); if (cleanInsn == null) { return null; @@ -54,12 +54,12 @@ public Configuration resolve(MixinData mixin, MixinContext context, Configuratio } private MethodInsnNode resolveTargetCallInsn(MethodNode dirtyTargetMethod, AbstractInsnNode cleanInjectionInsn, MixinContext context, String injectionPointTarget) { - AbstractInsnNode nextCallCandidate = findCandidates(MethodCallAnalyzer.findBackwardsInstructions(cleanInjectionInsn).inverse(), dirtyTargetMethod, List::getLast); + AbstractInsnNode nextCallCandidate = findCandidates(MethodInsnMatcher.findBackwardsInstructions(cleanInjectionInsn).inverse(), dirtyTargetMethod, List::getLast); if (nextCallCandidate != null) { return findReplacementInjectionPoint(nextCallCandidate, AbstractInsnNode::getNext, context, injectionPointTarget); } else { - AbstractInsnNode previousCallCandidate = findCandidates(MethodCallAnalyzer.findForwardInstructions(cleanInjectionInsn), dirtyTargetMethod, List::getFirst); + AbstractInsnNode previousCallCandidate = findCandidates(MethodInsnMatcher.findForwardInstructions(cleanInjectionInsn), dirtyTargetMethod, List::getFirst); if (previousCallCandidate != null) { return findReplacementInjectionPoint(previousCallCandidate, AbstractInsnNode::getPrevious, context, injectionPointTarget); } @@ -79,7 +79,7 @@ private static AbstractInsnNode findCandidates(InstructionMatcher cleanMatcher, continue; } - InstructionMatcher dirtyMatcher = MethodCallAnalyzer.findForwardInstructionsDirect(insn); + InstructionMatcher dirtyMatcher = MethodInsnMatcher.findForwardInstructionsDirect(insn); if (cleanMatcher.test(dirtyMatcher, InsnComparator.IGNORE_VAR_INDEX)) { // Find first method call past matched instruction AbstractInsnNode lastInsn = selector.apply(dirtyMatcher.after()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java index 5d5e6cb2..c802937e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java @@ -24,14 +24,14 @@ public class AtVariableAssignStoreSubResolver implements SubResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { - if (!clean.getAtData().getValue().equals(AT_VAL_INVOKE)) return null; + public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + if (!recipe.clean().getAtData().getValue().equals(AT_VAL_INVOKE)) return null; - MethodContext.TargetPair cleanPair = context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); + MethodContext.TargetPair cleanPair = recipe.getCleanTarget(); AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanPair); if (cleanInsn == null) return null; - MethodContext.TargetPair dirtyPair = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + MethodContext.TargetPair dirtyPair = recipe.getDirtyTarget(); if (dirtyPair == null) return null; // Check that the following instruction is a store operation @@ -76,7 +76,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Configuratio // All checks have passed, proceed to patch method return MutableConfiguration.create() - .setAtData(clean.getAtData().withTarget(previousMethodCall)); + .setAtData(recipe.clean().getAtData().withTarget(previousMethodCall)); } private static List findStoreInsns(InsnList insns, int index) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java new file mode 100644 index 00000000..52e239d4 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java @@ -0,0 +1,250 @@ +package org.sinytra.adapter.next.pipeline.resolver.injection; + +import com.google.common.collect.Multimap; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.ann.ConstantData; +import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup; +import org.sinytra.adapter.next.env.param.Parameter; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.processor.wrapop.WrapOpSurgeon; +import org.sinytra.adapter.next.pipeline.resolver.SubResolver; +import org.sinytra.adapter.patch.analysis.MethodLabelComparator; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.util.MethodQualifier; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_ORDINAL; + +public abstract class ComparingInjectionPointResolver implements SubResolver { + + @Nullable + protected AbstractInsnNode prepare(MixinContext context, Recipe recipe) { + MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + if (dirtyTarget == null) return null; + + MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + if (cleanTarget == null) return null; + + return context.methods().findInjectionTargetInsn(cleanTarget); + } + + public static class Inject extends ComparingInjectionPointResolver { + @Nullable + @Override + public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + if (cleanTarget == null) return null; + + AbstractInsnNode cleanInsn = prepare(context, recipe); + MethodLabelComparator.ComparisonResult comparisonResult = MethodLabelComparator.findPatchedLabels(cleanInsn, context.legacy()); + if (comparisonResult == null) return null; + + List> hunkLabels = comparisonResult.patchedLabels(); + + ClassNode cleanTargetClass = cleanTarget.classNode(); + for (List insns : hunkLabels) { + for (AbstractInsnNode insn : insns) { + if (insn instanceof MethodInsnNode minsn && minsn.getOpcode() == Opcodes.INVOKESTATIC && !minsn.owner.equals(cleanTargetClass.name)) { + Configuration result = attemptExtractMixin(minsn, context, recipe.clean()); + if (result != null) { + return result; + } + } + } + } + + // If extraction fails, fall back to injecting at the nearest method call in dirty code + for (List insns : hunkLabels) { + for (AbstractInsnNode insn : insns) { + if (insn instanceof MethodInsnNode minsn) { + return MutableConfiguration.create() + .setAtData(new AtData(AT_VAL_INVOKE, minsn)); + } + } + } + return null; + } + + private static Configuration attemptExtractMixin(MethodInsnNode minsn, MixinContext context, Configuration clean) { + // Looks like some code was moved into a static method outside this class + // Attempt extracting mixin + MethodContext.TargetPair target = context.methods().findMethodPair(context.dirtyLookup(), MethodQualifier.create(minsn)); + if (target == null) return null; + +// MethodUpgrader.adjustInjectorOrdinalForNewMethod(minsn, context.legacy()); FIXME + List newTargetInsns = context.methods().findInjectionTargetInsns(target, true); + if (newTargetInsns.isEmpty()) return null; + + return MutableConfiguration.create() + .setTargetClass(target.classNode().name) + .setTargetMethod(minsn) + .setAtData(clean.getAtData().withOrdinal(null)) // TODO Find new ordinal + .setProperty(Configuration.SpecialKeys.EXTRACT_TARGET, minsn); + } + } + + public static class WrapOperation extends ComparingInjectionPointResolver { + @Nullable + @Override + public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + if (dirtyTarget == null) return null; + + AbstractInsnNode cleanInsn = prepare(context, recipe); + if (!(cleanInsn instanceof MethodInsnNode minsn)) return null; + + MethodLabelComparator.ComparisonResult comparisonResult = MethodLabelComparator.findPatchedLabels(cleanInsn, context.legacy()); + if (comparisonResult == null) return null; + + List> hunkLabels = comparisonResult.patchedLabels(); + + return handleWrapOperationToInstanceOf(recipe, minsn, comparisonResult.cleanLabel(), hunkLabels, context) + .or(() -> handleWrapOperationAdaptedTarget(hunkLabels)) + .or(() -> handleWrapOperationNewInjectionPoint(minsn, comparisonResult.cleanLabel(), hunkLabels)) + .or(() -> handleTargetModification(hunkLabels, dirtyTarget, context)) + .orElse(null); + } + + private static Optional handleWrapOperationToInstanceOf(Recipe recipe, MethodInsnNode cleanInjectionInsn, List cleanLabel, List> hunkLabels, MixinContext context) { + if (hunkLabels.size() != 1 || !(cleanLabel.getLast() instanceof JumpInsnNode) || cleanLabel.stream().anyMatch(i -> i instanceof TypeInsnNode)) + return Optional.empty(); + + List dirtyLabel = hunkLabels.getFirst(); + if (!(dirtyLabel.getLast() instanceof JumpInsnNode)) return Optional.empty(); + + List instanceOfCalls = dirtyLabel.stream() + .filter(TypeInsnNode.class::isInstance) + .map(TypeInsnNode.class::cast) + .toList(); + if (instanceOfCalls.size() != 1) return Optional.empty(); + TypeInsnNode instanceOfCall = instanceOfCalls.getFirst(); + + MethodNode methodNode = context.methodNode(); + LocalVariableLookup mixinLocals = new LocalVariableLookup(methodNode); + LocalVariableNode instanceLocal = mixinLocals.getByParameterOrdinal(0); + + Configuration clean = recipe.clean(); + List inheritedParams = clean.getParameters().getTypes(ParamGroup.METHOD_PARAMS); + Multimap usedVars = WrapOpSurgeon.getUsedVars(mixinLocals, inheritedParams, context); + + MutableConfiguration config = recipe.dirty().subConfig() + .removeProperty(Keys.TARGET_AT) + .setProperty(Keys.TARGET_CONSTANT, ConstantData.classValue(Type.getObjectType(instanceOfCall.desc))) + .inheritParameters() + .inheritReturnType(); + MethodParameters parameters = config.getParameters(); + Parameter newInstanceParam = Parameter.simple(MixinConstants.OBJECT_TYPE); + parameters.set(ParamGroup.METHOD_PARAMS, List.of(newInstanceParam)); + + if (usedVars.containsKey(instanceLocal.index)) { + MethodContext methodContext = context.legacy(); + List originalCallArgs = MethodCallAnalyzer.getMethodCallSrcInsns(methodContext.findCleanInjectionTarget().methodNode(), cleanInjectionInsn); + int cleanOrdinal = methodContext.cleanLocalsTable().getTypedOrdinal(methodContext.cleanLocalsTable().getByIndex(((VarInsnNode) originalCallArgs.getFirst()).var)).orElse(-1); + if (cleanOrdinal == -1) return Optional.empty(); + + LocalVariableNode dirtyLocal = methodContext.dirtyLocalsTable().getByTypedOrdinal(Type.getType(instanceLocal.desc), cleanOrdinal).orElse(null); + if (dirtyLocal == null) return Optional.empty(); + + Parameter replacementInstanceParam = Parameter.builder(dirtyLocal.desc) + .annotate(MixinConstants.LOCAL, b -> b + .put(PROPERTY_ORDINAL, cleanOrdinal)) + .build(); + parameters.add(ParamGroup.LOCALS, replacementInstanceParam); + // TODO exclude original.call(...) insns from being mapped + parameters.mapParameter(newInstanceParam, replacementInstanceParam); + } + + // TODO Find a way to get rid of this ugly hack + // Use "state.getBlock()" as the new Block parameter + if (instanceOfCall.getPrevious() instanceof MethodInsnNode m) { + String loadedType = Type.getReturnType(m.desc).getDescriptor(); + for (int paramVar : usedVars.keySet()) { + if (paramVar == instanceLocal.index) { + continue; + } + + LocalVariableNode node = mixinLocals.getByIndex(paramVar); + if (!loadedType.equals(node.desc)) return Optional.empty(); + + int paramOrdinal = mixinLocals.getParameterOrdinal(node); + Parameter oldParam = clean.getParameters().get(ParamGroup.METHOD_PARAMS).get(paramOrdinal); + parameters.mapParameter(oldParam, newInstanceParam); + } + } + + return Optional.of(config); + } + + private static Optional handleWrapOperationAdaptedTarget(List> hunkLabels) { + if (hunkLabels.size() != 1) return Optional.empty(); + + List methodCalls = hunkLabels.getFirst().stream() + .filter(MethodInsnNode.class::isInstance) + .map(MethodInsnNode.class::cast) + .toList(); + if (methodCalls.size() != 1) return Optional.empty(); + MethodInsnNode insn = methodCalls.getLast(); + + return Optional.of(MutableConfiguration.create() + .setAtData(new AtData(AT_VAL_INVOKE, insn))); + } + + private static Optional handleWrapOperationNewInjectionPoint(MethodInsnNode cleanInjectionInsn, List cleanLabel, List> hunkLabels) { + if (hunkLabels.size() != 1) + return Optional.empty(); + + Type cleanReturnType = Type.getReturnType(cleanInjectionInsn.desc); + List dirtyLabel = hunkLabels.getFirst(); + List cleanMethodCalls = cleanLabel.stream() + .filter(i -> i instanceof MethodInsnNode m + && m.owner.equals(cleanInjectionInsn.owner) + && Type.getReturnType(m.desc).equals(cleanReturnType)) + .map(i -> ((MethodInsnNode) i).name) + .toList(); + + List methodCalls = dirtyLabel.stream() + .filter(i -> i instanceof MethodInsnNode m && m.owner.equals(cleanInjectionInsn.owner) + && Type.getReturnType(m.desc).equals(cleanReturnType) + && !cleanMethodCalls.contains(m.name)) + .map(MethodInsnNode.class::cast) + .toList(); + if (methodCalls.size() != 1) return Optional.empty(); + + MethodInsnNode dirtyMinsn = methodCalls.getFirst(); + return Optional.of(MutableConfiguration.create() + .setAtData(new AtData(AT_VAL_INVOKE, dirtyMinsn))); + } + + private static Optional handleTargetModification(List> hunkLabels, MethodContext.TargetPair dirtyTarget, MixinContext context) { + ClassNode dirtyClass = dirtyTarget.classNode(); + return hunkLabels.stream() + .flatMap(Collection::stream) + .filter(insn -> insn instanceof MethodInsnNode minsn && minsn.owner.equals(dirtyClass.name)) + .map(MethodInsnNode.class::cast) + .filter(minsn -> { + MethodContext.TargetPair pair = context.methods().findMethodPair(context.dirtyLookup(), MethodQualifier.create(minsn)); + return pair != null && context.methods().hasInjectionTargetInsns(pair); + }) + .map(minsn -> MutableConfiguration.create() + .setAtData(new AtData(AT_VAL_INVOKE, minsn))) + .findFirst(); + } + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java index 5e8f4a08..ccaa478b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java @@ -4,10 +4,10 @@ import org.objectweb.asm.tree.AbstractInsnNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; @@ -18,23 +18,20 @@ public InjectionPointResolver() { } @Override - protected boolean canApply(MixinData mixin, Configuration clean, Configuration dirty) { - return dirty.getAtData() == null; + protected boolean canApply(MixinData mixin, Recipe recipe) { + return recipe.dirty().getAtData() == null; } @Nullable @Override - protected Configuration tryReuse(MixinContext context, Configuration clean, Configuration dirty) { - MethodQualifier dirtyQualifier = dirty.getTargetMethod(); - if (dirtyQualifier == null) return null; - - MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), dirtyQualifier); + protected Configuration tryReuse(MixinContext context, Recipe recipe) { + MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); if (dirtyTarget == null) return null; // Try reusing the original List insns = context.methods().findInjectionTargetInsns(dirtyTarget); if (!insns.isEmpty()) { - return dirty.subConfig() + return recipe.dirty().subConfig() .inheritAtData(); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java index 19ff4a17..d3389a32 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java @@ -9,13 +9,13 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.WeighedDisambiguation; import org.sinytra.adapter.next.env.ann.MixinData; -import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -26,19 +26,19 @@ import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; public class InjectionPointSubResolvers { - public static final SubResolver REPLACED_TYPE = (MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) -> { - if (!clean.getAtData().getValue().equals(AT_VAL_INVOKE)) return null; + public static final SubResolver REPLACED_TYPE = (MixinData mixin, MixinContext context, Recipe recipe) -> { + if (!recipe.clean().getAtData().getValue().equals(AT_VAL_INVOKE)) return null; - MethodContext.TargetPair cleanPair = context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); - MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + MethodContext.TargetPair cleanPair = recipe.getCleanTarget(); + MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); // Find single clean target minsn List insns = context.methods().findInjectionTargetInsns(cleanPair); if (insns.isEmpty() || !(insns.getFirst() instanceof MethodInsnNode cleanInsn)) return null; - InstructionMatcher cleanMatcher = MethodCallAnalyzer.findSurroundingInstructions(cleanInsn); - Multimap dirtyCalls = MethodCallAnalyzer.getMethodCalls(dirtyTarget.methodNode(), new ArrayList<>()); + InstructionMatcher cleanMatcher = MethodInsnMatcher.findSurroundingInstructions(cleanInsn); + Multimap dirtyCalls = MethodAnalyzer.getMethodCalls(dirtyTarget.methodNode(), new ArrayList<>()); List dirtyMatchers = dirtyCalls.values().stream() - .map(MethodCallAnalyzer::findSurroundingInstructions) + .map(MethodInsnMatcher::findSurroundingInstructions) .toList(); WeighedDisambiguation magicBlackBox = WeighedDisambiguation.builder() @@ -51,7 +51,7 @@ public class InjectionPointSubResolvers { MethodQualifier replacement = magicBlackBox.findBestMatch(); if (replacement != null) { return MutableConfiguration.create() - .setAtData(clean.getAtData().withTarget(replacement)); + .setAtData(recipe.clean().getAtData().withTarget(replacement)); } return null; @@ -81,18 +81,18 @@ private static List testOverloadedMethods(MixinContext context, return List.of(); } - List cleanParams = MethodParameters.getParameterTypes(cleanInsn.desc); + List cleanParams = Parameters.getParameterTypes(cleanInsn.desc); List methods = dirtyClass.methods.stream() .filter(m -> { if (cleanPair.classNode().methods.stream() .noneMatch(c -> c.name.equals(m.name) && c.desc.equals(m.desc)) && m.name.equals(cleanInsn.name) ) { - List dirtyParams = MethodParameters.getParameterTypes(m.desc); + List dirtyParams = Parameters.getParameterTypes(m.desc); return dirtyParams.size() > cleanParams.size() && dirtyParams.subList(0, cleanParams.size()).equals(cleanParams); } return false; }) - .filter(m -> MethodCallAnalyzer.containsMethodCall(dirtyPair.methodNode(), MethodQualifier.create(m))) + .filter(m -> MethodAnalyzer.containsMethodCall(dirtyPair.methodNode(), MethodQualifier.create(m))) .toList(); return methods.size() == 1 ? List.of(MethodQualifier.create(dirtyClass, methods.getFirst())) : List.of(); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java index 311141a6..0f70f7cc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java @@ -7,7 +7,6 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinData; -import org.sinytra.adapter.next.env.ann.ModifyVariableMixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; @@ -25,22 +24,18 @@ public class ModifyVarInjectionPointSubResolver implements SubResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { - if (!(mixin instanceof ModifyVariableMixinData mvdata) || !clean.getAtData().getValue().equals(AT_VAL_STORE)) { - return null; - } - MethodContext.TargetPair pair = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + if (!recipe.clean().getAtData().getValue().equals(AT_VAL_STORE)) return null; + MethodContext.TargetPair dirtyPair = recipe.getDirtyTarget(); + if (dirtyPair == null) return null; + // Find replacement - return findComparableReplacement(mvdata, context, clean, pair, dirty); - } - - private static Configuration findComparableReplacement(ModifyVariableMixinData mixin, MixinContext context, Configuration clean, MethodContext.TargetPair dirtyPair, Configuration dirty) { - if (mixin.ordinal().isEmpty()) return null; + Integer ordinal = mixin.getProperty(ORDINAL).orElse(null); + if (ordinal == null) return null; - int ordinal = mixin.ordinal().getAsInt(); Type varType = Type.getReturnType(context.methodNode().desc); - MethodContext.TargetPair cleanPair = context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); + MethodContext.TargetPair cleanPair = recipe.getCleanTarget(); LocalVariableLookup lookup = new LocalVariableLookup(cleanPair.methodNode()); LocalVariableNode desired = lookup.getByTypedOrdinal(varType, ordinal).orElseThrow(); @@ -60,7 +55,7 @@ private static Configuration findComparableReplacement(ModifyVariableMixinData m if (lvs.size() == 1) { int dirtyOrdinal = dirtyLookup.getOrdinal(lvs.getFirst()); - return dirty.subConfig() + return recipe.dirty().subConfig() .setProperty(ORDINAL, dirtyOrdinal) .setTargetMethod(method) .inheritAtData(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java index 6693c08a..fcd303e2 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java @@ -2,6 +2,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.Configurations; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.MixinData; @@ -10,7 +11,7 @@ import org.sinytra.adapter.next.pipeline.resolver.Resolver; import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; @@ -33,11 +34,12 @@ public record ResolverSyntheticInstanceof(boolean skipInsnComparison) implements Resolver { @Override - public ResolutionResult resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { - if (!context.legacy().hasInjectionPointValue(AT_VAL_INVOKE)) return ResolutionResult.pass(); + public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe) { + if (!context.legacy().hasInjectionPointValue(AT_VAL_INVOKE)) + return ResolutionResult.pass(); - MethodContext.TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); - MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); AbstractInsnNode targetInsn = context.methods().findInjectionTargetInsn(cleanTarget); if (targetInsn == null) return ResolutionResult.pass(); @@ -46,14 +48,14 @@ public ResolutionResult resolve(MixinData mixin, MixinContext context, Configura // Ensure label contain an if statement if (!(jumpInsn instanceof JumpInsnNode)) return ResolutionResult.pass(); - InstructionMatcher cleanMatcher = MethodCallAnalyzer.findForwardInstructions(targetInsn); + InstructionMatcher cleanMatcher = MethodInsnMatcher.findForwardInstructions(targetInsn); int firstOp = cleanMatcher.after().getFirst().getOpcode(); // Find equivalent dirty code point InsnList dirtyInsns = dirtyTarget.methodNode().instructions; for (AbstractInsnNode insn : dirtyInsns) { if (insn.getOpcode() == firstOp) { AbstractInsnNode nextLabel = findInsnAfterLabel(insn); - InstructionMatcher dirtyMatcher = MethodCallAnalyzer.findForwardInstructions(nextLabel); + InstructionMatcher dirtyMatcher = MethodInsnMatcher.findForwardInstructions(nextLabel); if (cleanMatcher.test(dirtyMatcher)) { // ModifyExpressionValue doesn't include the original instanceof call, so we can skip comparing instructions if (this.skipInsnComparison) { @@ -63,7 +65,7 @@ public ResolutionResult resolve(MixinData mixin, MixinContext context, Configura } int ordinal = getInstanceofOrdinal(dirtyInsns, instanceOfInsn); - Configuration config = dirty.subConfig() + Configuration config = recipe.dirty().subConfig() .setMixinType(MixinConstants.MODIFY_INSTANCEOF_VAL) .inheritTargetClass() .inheritTargetMethod() @@ -71,7 +73,7 @@ public ResolutionResult resolve(MixinData mixin, MixinContext context, Configura .inheritParameters() .inheritReturnType(); - return ResolutionResult.finalize(config); + return ResolutionResult.replace(config); } // Found the code point, now determine the contents of the updated if statement @@ -99,13 +101,7 @@ public ResolutionResult resolve(MixinData mixin, MixinContext context, Configura // Disable mixin. Goodbye. if (finalCleanMatcher.test(finalDirtyMatcher, InsnComparator.IGNORE_VAR_INDEX)) { - // TODO Come up with a voting system for validation so that we can skip checks for unused props when delete is enabled - return ResolutionResult.finalize(dirty.subConfig() - .inheritTargetMethod() - .inheritAtData() - .inheritParameters() - .inheritReturnType() - .setShouldDelete(true)); + return ResolutionResult.replace(Configurations.DELETE); } } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java index fe33f989..72533fb1 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java @@ -26,15 +26,14 @@ import java.util.Optional; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.SLICE; public class SliceBoundaryResolver implements Resolver { @Override - public ResolutionResult resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { - MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe) { + MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); - SliceData slice = clean.getProperty(SLICE).orElse(null); + SliceData slice = recipe.clean().getProperty(SLICE).orElse(null); if (slice == null || passesSliceCheck(slice, context, dirtyTarget)) return ResolutionResult.pass(); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/SplitMethodCancellationHelper.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java similarity index 68% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/SplitMethodCancellationHelper.java rename to definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java index fa800bdb..26d46844 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynfix/SplitMethodCancellationHelper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.dynfix; +package org.sinytra.adapter.next.pipeline.resolver.target; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; @@ -7,7 +7,9 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinClassGenerator; import org.sinytra.adapter.patch.api.MixinConstants; @@ -18,19 +20,21 @@ public final class SplitMethodCancellationHelper { - public static void handle(Object transform, MethodContext methodContext, MethodNode newTarget) { - MethodContext.TargetPair originalTarget = methodContext.findDirtyInjectionTarget(); + public static void handle(Object transform, MixinContext context, Recipe recipe, MethodNode newTarget) { + MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + MethodContext.TargetPair originalTarget = recipe.getDirtyTarget(); + ClassNode originalClassTarget = originalTarget.classNode(); MethodNode originalMethodTarget = originalTarget.methodNode(); - if (!MethodCallAnalyzer.isDirtyDeprecatedMethod(methodContext.findCleanInjectionTarget().methodNode(), originalMethodTarget) || Type.getReturnType(originalMethodTarget.desc) != Type.VOID_TYPE) { + if (!MethodAnalyzer.isDirtyDeprecatedMethod(cleanTarget.methodNode(), originalMethodTarget) || Type.getReturnType(originalMethodTarget.desc) != Type.VOID_TYPE) { return; } - MixinClassGenerator generator = methodContext.patchContext().environment().classGenerator(); - ClassNode generatedTarget = generator.getOrGenerateMixinClass(methodContext.getMixinClass(), originalClassTarget.name, null); + MixinClassGenerator generator = context.patchContext().environment().classGenerator(); + ClassNode generatedTarget = generator.getOrGenerateMixinClass(context.classNode(), originalClassTarget.name, null); - List invocations = MethodCallAnalyzer.collectMethodInvocations(originalClassTarget, originalMethodTarget); + List invocations = MethodAnalyzer.collectMethodInvocations(originalClassTarget, originalMethodTarget); if (invocations == null) { return; } @@ -41,16 +45,16 @@ public static void handle(Object transform, MethodContext methodContext, MethodN FieldNode trackerField = (FieldNode) generatedTarget.visitField(Opcodes.ACC_PRIVATE, fieldName, Type.BOOLEAN_TYPE.getDescriptor(), null, null); for (int i = index + 1; i < invocations.size(); i++) { - generateCancellerMethod(generatedTarget, trackerField, originalClassTarget, invocations.get(i), methodContext, i == invocations.size() - 1); + generateCancellerMethod(generatedTarget, trackerField, originalClassTarget, invocations.get(i), context, i == invocations.size() - 1); } - methodContext.recordAudit(transform, "Generate cancellation handler mixin"); +// context.recordAudit(transform, "Generate cancellation handler mixin"); } - private static void generateCancellerMethod(ClassNode generatedTarget, FieldNode trackerField, ClassNode originalClassTarget, MethodNode newTarget, MethodContext methodContext, boolean reset) { - String name = methodContext.getMixinMethod().name + "$adapter$canceller$" + AdapterUtil.randomString(5); - String desc = Type.getMethodDescriptor(Type.VOID_TYPE, AdapterUtil.CI_TYPE); - MethodNode invokerMixinMethod = (MethodNode) generatedTarget.visitMethod(Opcodes.ACC_PRIVATE | (methodContext.isStatic() ? Opcodes.ACC_STATIC : 0), name, desc, null, null); + private static void generateCancellerMethod(ClassNode generatedTarget, FieldNode trackerField, ClassNode originalClassTarget, MethodNode newTarget, MixinContext context, boolean reset) { + String name = context.methodNode().name + "$adapter$canceller$" + AdapterUtil.randomString(5); + String desc = Type.getMethodDescriptor(Type.VOID_TYPE, MixinConstants.CI_TYPE); + MethodNode invokerMixinMethod = (MethodNode) generatedTarget.visitMethod(Opcodes.ACC_PRIVATE | (context.isStatic() ? Opcodes.ACC_STATIC : 0), name, desc, null, null); { AnnotationVisitor injectAnn = invokerMixinMethod.visitAnnotation(MixinConstants.INJECT, true); { @@ -86,15 +90,15 @@ private static void generateCancellerMethod(ClassNode generatedTarget, FieldNode } gen.newLabel(); gen.loadArg(0); - gen.invokeVirtual(AdapterUtil.CI_TYPE, new Method("cancel", "()V")); + gen.invokeVirtual(MixinConstants.CI_TYPE, new Method("cancel", "()V")); } gen.visitLabel(endLabel); gen.returnValue(); gen.newLabel(); gen.endMethod(); // Modify mixin to set the field value - MethodQualifier qualifier = new MethodQualifier(AdapterUtil.CI_TYPE.getDescriptor(), "cancel", "()V"); - InsnList methodInsns = methodContext.getMixinMethod().instructions; + MethodQualifier qualifier = new MethodQualifier(MixinConstants.CI_TYPE.getDescriptor(), "cancel", "()V"); + InsnList methodInsns = context.methodNode().instructions; for (AbstractInsnNode insn : methodInsns) { if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { InsnList list = new InsnList(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java index 90832002..ad479b51 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java @@ -13,9 +13,9 @@ import org.sinytra.adapter.next.pipeline.resolver.SubResolver; import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.transformer.dynfix.SplitMethodCancellationHelper; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.*; @@ -26,20 +26,20 @@ */ public class SplitTargetMethodSubResolver implements SubResolver { @Override - public Configuration resolve(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) { - MethodContext.TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); - MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), clean.getTargetMethod()); - if (dirtyTarget == null) return null; + public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), recipe.clean().getTargetMethod()); + if (cleanTarget == null || dirtyTarget == null) return null; - List candidates = disambiguate(locateCandidates(context, dirtyTarget), context, cleanTarget); + List candidates = disambiguate(locateCandidates(context, cleanTarget, dirtyTarget), context, cleanTarget); if (candidates.size() == 1) { MethodNode method = candidates.getFirst().method(); // methodContext.recordAudit(this, "Adjusting split method target to %s", newTarget); - // TODO - if (context.legacy().isCancellable()) { - SplitMethodCancellationHelper.handle(this, context.legacy(), method); + // TODO Move to processor + if (mixin.isCancellable()) { + SplitMethodCancellationHelper.handle(this, context, recipe, method); } return MutableConfiguration.create() @@ -49,52 +49,51 @@ public Configuration resolve(MixinData mixin, MixinContext context, Configuratio return null; } - private static List locateCandidates(MixinContext context, MethodContext.TargetPair dirtyTarget) { - MethodContext methodContext = context.legacy(); - - MethodNode cleanTargetMethod = methodContext.findCleanInjectionTarget().methodNode(); - ClassNode dirtyTargetClass = methodContext.findDirtyInjectionTarget().classNode(); - MethodNode dirtyTargetMethod = methodContext.findDirtyInjectionTarget().methodNode(); + private static List locateCandidates(MixinContext context, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget) { + MethodNode cleanTargetMethod = cleanTarget.methodNode(); + ClassNode dirtyTargetClass = dirtyTarget.classNode(); + MethodNode dirtyTargetMethod = dirtyTarget.methodNode(); // Check that a Deprecated annotation was added to the dirty method - if (!MethodCallAnalyzer.isDirtyDeprecatedMethod(cleanTargetMethod, dirtyTargetMethod)) { - return tryFindPartialCandidates(cleanTargetMethod, dirtyTargetClass, dirtyTargetMethod, methodContext); + if (!MethodAnalyzer.isDirtyDeprecatedMethod(cleanTargetMethod, dirtyTargetMethod)) { + return tryFindPartialCandidates(cleanTargetMethod, dirtyTargetClass, dirtyTargetMethod, context); } - List invocations = MethodCallAnalyzer.collectMethodInvocations(dirtyTargetClass, dirtyTargetMethod); + List invocations = MethodAnalyzer.collectMethodInvocations(dirtyTargetClass, dirtyTargetMethod); if (invocations == null) { return List.of(); } - List candidates = findInsnsCalls(invocations, methodContext); + List candidates = findInsnsCalls(invocations.stream() + .map(m -> new MethodContext.TargetPair(dirtyTargetClass, m)).toList(), context); // Attempt to find matching insns in lambdas if (candidates.isEmpty()) { - List nestedLambdas = invocations.stream() - .flatMap(m -> MethodCallAnalyzer.findLambdasInMethod(dirtyTarget.classNode(), m, null).stream()) - .map(s -> MethodQualifier.create(s).orElseThrow()) - .flatMap(s -> Optional.ofNullable(context.methods().findOwnMethodPair(context.dirtyLookup(), s)) - .map(MethodContext.TargetPair::methodNode) - .stream()) + List nestedLambdas = invocations.stream() + .flatMap(m -> MethodAnalyzer.findLambdasInMethod(dirtyTarget.classNode(), m, null).stream()) + .flatMap(s -> MethodQualifier.create(s).stream()) + .map(s -> context.methods().findOwnMethodPair(context.dirtyLookup(), s)) + .filter(Objects::nonNull) .toList(); - return findInsnsCalls(nestedLambdas, methodContext); + return findInsnsCalls(nestedLambdas, context); } return candidates; } // Handle cases where only part of the method is moved away - private static List tryFindPartialCandidates(MethodNode cleanTargetMethod, ClassNode dirtyTargetClass, MethodNode dirtyTargetMethod, MethodContext methodContext) { - Multimap cleanMethodCalls = MethodCallAnalyzer.getMethodCalls(cleanTargetMethod, new ArrayList<>()); - Multimap dirtyMethodCalls = MethodCallAnalyzer.getMethodCalls(dirtyTargetMethod, new ArrayList<>()); + private static List tryFindPartialCandidates(MethodNode cleanTargetMethod, ClassNode dirtyTargetClass, MethodNode dirtyTargetMethod, MixinContext context) { + Multimap cleanMethodCalls = MethodAnalyzer.getMethodCalls(cleanTargetMethod, new ArrayList<>()); + Multimap dirtyMethodCalls = MethodAnalyzer.getMethodCalls(dirtyTargetMethod, new ArrayList<>()); - List dirtyOnlyCalls = dirtyMethodCalls.entries().stream() + List dirtyOnlyCalls = dirtyMethodCalls.entries().stream() .filter(e -> !cleanMethodCalls.containsKey(e.getKey()) && e.getValue().owner.equals(dirtyTargetClass.name)) .map(Map.Entry::getValue) - .flatMap(i -> MethodCallAnalyzer.findMethodByName(dirtyTargetClass, i.name, i.desc).stream()) + .map(i -> context.methods().findOwnMethodPair(context.dirtyLookup(), MethodQualifier.create(i))) + .filter(Objects::nonNull) .toList(); - return findInsnsCalls(dirtyOnlyCalls, methodContext); + return findInsnsCalls(dirtyOnlyCalls, context); } // If multiple candidates have been found, try comparing the surrounding method instructions to find one match @@ -108,12 +107,12 @@ private static List disambiguate(List candidat return candidates; } - InstructionMatcher cleanMatcher = MethodCallAnalyzer.findSurroundingInstructions(cleanInsns.getFirst(), 5); + InstructionMatcher cleanMatcher = MethodInsnMatcher.findSurroundingInstructions(cleanInsns.getFirst(), 5); List matchingCandidates = candidates.stream() .filter(method -> method.insns().size() == 1) .filter(method -> { - InstructionMatcher matcher = MethodCallAnalyzer.findSurroundingInstructions(method.insns().getFirst(), 5); + InstructionMatcher matcher = MethodInsnMatcher.findSurroundingInstructions(method.insns().getFirst(), 5); return cleanMatcher.test(matcher, InsnComparator.IGNORE_VAR_INDEX); }) .toList(); @@ -125,12 +124,11 @@ private static List disambiguate(List candidat return candidates; } - private static List findInsnsCalls(List methods, MethodContext methodContext) { - ClassNode dirtyTargetClass = methodContext.findDirtyInjectionTarget().classNode(); + private static List findInsnsCalls(List methods, MixinContext context) { return methods.stream() - .map(method -> { - List insns = methodContext.findInjectionTargetInsns(new MethodContext.TargetPair(dirtyTargetClass, method)); - return !insns.isEmpty() ? new CandidateMethod(method, insns) : null; + .map(pair -> { + List insns = context.methods().findInjectionTargetInsns(pair); + return !insns.isEmpty() ? new CandidateMethod(pair.methodNode(), insns) : null; }) .filter(Objects::nonNull) .toList(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java index 14002378..6f70906f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java @@ -2,6 +2,7 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinData; +import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; import org.sinytra.adapter.patch.api.MethodContext; @@ -15,27 +16,27 @@ public TargetMethodResolver() { } @Override - protected boolean canApply(MixinData mixin, Configuration clean, Configuration dirty) { - return dirty.getTargetMethod() == null; + protected boolean canApply(MixinData mixin, Recipe recipe) { + return recipe.dirty().getTargetMethod() == null; } @Override - protected Configuration tryReuse(MixinContext context, Configuration clean, Configuration dirty) { - MethodQualifier cleanQualifier = clean.getTargetMethod(); + protected Configuration tryReuse(MixinContext context, Recipe recipe) { + MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); MethodContext.TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); if (target != null && context.methods().hasInjectionTargetInsns(target)) { - return dirty.subConfig() + return recipe.dirty().subConfig() .inheritTargetMethod(); } return null; } @Override - protected Configuration useFallback(MixinContext context, Configuration clean, Configuration dirty) { - MethodQualifier cleanQualifier = clean.getTargetMethod(); + protected Configuration useFallback(MixinContext context, Recipe recipe) { + MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); MethodContext.TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); if (target != null) { - return dirty.subConfig() + return recipe.dirty().subConfig() .inheritTargetMethod(); } return null; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java index 96fb3c9a..e478cc39 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java @@ -33,14 +33,14 @@ public class TargetMethodSubResolvers { *
* DIRTY: Lnet/minecraft/server/level/ServerEntity;sendPairingData(Lnet/minecraft/server/level/ServerPlayer;Lnet/neoforged/neoforge/network/bundle/PacketAndPayloadAcceptor;)V */ - public static final SubResolver CHANGED_METHOD_PARAMS = (MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) -> { - MethodQualifier cleanQualifier = clean.getTargetMethod(); + public static final SubResolver CHANGED_METHOD_PARAMS = (MixinData mixin, MixinContext context, Recipe recipe) -> { + MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); Pair> candidates = context.methods().findOwnMethodsByName(context.dirtyLookup(), cleanQualifier); if (candidates == null) return null; // Find single matching candidate - Configuration resolved = resolveReplacementCandidate(mixin, context, clean, dirty, recipe, candidates.getFirst(), candidates.getSecond()); + Configuration resolved = resolveReplacementCandidate(mixin, context, recipe, candidates.getSecond()); if (resolved == null) return null; // Only apply single candidate change when the target desc has changed @@ -54,8 +54,8 @@ public class TargetMethodSubResolvers { /** * Handle cases where the target instructions have been moved into a lambda inside the target method */ - public static final SubResolver MOVED_INTO_LAMBDA = (MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe) -> { - MethodQualifier cleanQualifier = clean.getTargetMethod(); + public static final SubResolver MOVED_INTO_LAMBDA = (MixinData mixin, MixinContext context, Recipe recipe) -> { + MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); MethodContext.TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); if (target == null) return null; @@ -79,7 +79,7 @@ public class TargetMethodSubResolvers { }; @Nullable - private static Configuration resolveReplacementCandidate(MixinData mixin, MixinContext context, Configuration clean, Configuration dirty, Recipe recipe, ClassNode classNode, List methods) { + private static Configuration resolveReplacementCandidate(MixinData mixin, MixinContext context, Recipe recipe, List methods) { if (methods.size() == 1) { return MutableConfiguration.create() .setTargetMethod(methods.getFirst()); @@ -89,12 +89,13 @@ private static Configuration resolveReplacementCandidate(MixinData mixin, MixinC List> valid = methods.stream() .sorted(Comparator.comparing(m -> m.desc).reversed()) - .>flatMap(m -> - resolver.resolve(mixin, context, clean, dirty.copy().setTargetMethod(m), recipe) + .>flatMap(m -> { + Configuration dirtyCopy = recipe.dirty().copy().setTargetMethod(m); + return resolver.resolve(mixin, context, recipe.withDirtyConfig(dirtyCopy)) .maybePatch() .stream() - .map(c -> Pair.of(m, c.subConfig().setTargetMethod(m))) - ) + .map(c -> Pair.of(m, c.subConfig().setTargetMethod(m))); + }) .toList(); if (valid.size() == 1) { return valid.getFirst().getSecond(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java index 68a1415f..43e8fada 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java @@ -3,70 +3,74 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ann.InjectMixinData; -import org.sinytra.adapter.next.env.ann.SliceData; +import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.config.PropertyKey; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; +import org.sinytra.adapter.next.pipeline.resolver.injection.ComparingInjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; +import java.util.Set; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; -public class InjectMixin implements MixinType { +public class InjectMixin implements MixinType { @Override public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } @Override - public InjectMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { - List slice = handle.getNestedList(PROPERTY_SLICE).stream() - .map(s -> SliceData.parse(s, context)) - .toList(); - return new InjectMixinData(targetClass, targetMethod, atData, slice); + public Set> requestProperties() { + return Set.of(Keys.SLICES, Keys.CANCELLABLE); } @Override - public void preProcess(InjectMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { recipe.resolvers().getOrThrow(InjectionPointResolver.class) .addSubResolver(new AtVariableAssignStoreSubResolver()) + .addSubResolver(new ComparingInjectionPointResolver.Inject()) .addSubResolver(new ArbitraryInjectionPointSubResolver()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(METHOD_PARAMS, CI_CIR, LOCALS))); - if (!mixin.getSlice().isEmpty()) { -// clean.setProperty("slice", mixin.getSlice()); TODO Handle multile and single slices using one interface - } + // TODO Handle slices +// mixin.getProperty(Configuration.Keys.SLICES) +// .ifPresent(p -> clean.setProperty(Configuration.Keys.SLICES, p)); + + return TxResult.SUCCESS; } @Override - public void postProcess(InjectMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { dirty.setReturnType(Type.VOID_TYPE); + if (dirty.getTargetMethod() == null) { + return TxResult.SUCCESS; + } - if (dirty.getTargetMethod() != null) { - if (dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { - dirty.inheritParameters(); + if (dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { + dirty.inheritParameters(); + } else { + List cleanParams = clean.getParameters().getTypes(METHOD_PARAMS); + if (!cleanParams.isEmpty()) { + MethodParameters newParams = clean.getParameters().copy(); + List dirtyTargetMethodParams = Parameters.getParameterTypes(dirty.getTargetMethod().desc()); + newParams.setTypes(METHOD_PARAMS, dirtyTargetMethodParams); + dirty.setParameters(newParams); } else { - List cleanParams = clean.getParameters().get(METHOD_PARAMS); - if (!cleanParams.isEmpty()) { - MethodParameters newParams = MethodParameters.create(context.methodNode(), List.of(METHOD_PARAMS, CI_CIR, LOCALS)); - List dirtyTargetMethodParams = MethodParameters.getParameterTypes(dirty.getTargetMethod().desc()); - newParams.set(METHOD_PARAMS, dirtyTargetMethodParams); - - dirty.setParameters(newParams); - } + dirty.inheritParameters(); } } + + return TxResult.SUCCESS; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java b/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java index c2a6e653..d6dae62d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java @@ -1,15 +1,15 @@ package org.sinytra.adapter.next.type; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.next.pipeline.config.PropertyKey; + +import java.util.Set; /** * Handles configuration and behavior specific to a Mixin type @@ -17,11 +17,11 @@ public interface MixinType { PropertyContainerTemplate getConfigurationTemplate(); - T parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle); + default Set> requestProperties() { + return Set.of(); + } - // TODO Return success flag - void preProcess(T mixin, MixinContext context, MutableConfiguration clean, Recipe recipe); + TxResult preProcess(T mixin, MixinContext context, MutableConfiguration clean, Recipe recipe); - // TODO Return success flag - void postProcess(T mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); + TxResult postProcess(T mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java b/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java index d806afa3..83e56917 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java @@ -12,14 +12,21 @@ public class MixinTypes { private static final Map> MIXIN_TYPES = new HashMap<>(); + + public static final MixinType INJECT = new InjectMixin(); + public static final MixinType MODIFY_VAR = new ModifyVariableMixin(); + public static final MixinType MODIFY_ARG = new ModifyArgMixin(); + public static final MixinType REDIRECT = new RedirectMixin(); + public static final MixinType WRAP_OP = new WrapOperationMixin(); + public static final MixinType MODIFY_EXPR_VAL = new ModifyExpressionValueMixin(); static { - registerMixinType(Inject.class, new InjectMixin()); - registerMixinType(ModifyVariable.class, new ModifyVariableMixin()); - registerMixinType(ModifyArg.class, new ModifyArgMixin()); - registerMixinType(Redirect.class, new RedirectMixin()); - registerMixinType(MixinConstants.WRAP_OPERATION_INTERNAL_NAME, new WrapOperationMixin()); - registerMixinType(MixinConstants.MODIFY_EXPR_VAL_INTERNAL_NAME, new ModifyExpressionValueMixin()); + registerMixinType(Inject.class, INJECT); + registerMixinType(ModifyVariable.class, MODIFY_VAR); + registerMixinType(ModifyArg.class, MODIFY_ARG); + registerMixinType(Redirect.class, REDIRECT); + registerMixinType(MixinConstants.WRAP_OPERATION_INTERNAL_NAME, WRAP_OP); + registerMixinType(MixinConstants.MODIFY_EXPR_VAL_INTERNAL_NAME, MODIFY_EXPR_VAL); } @Nullable diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java index 7d7fd1b8..d1486be9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java @@ -5,51 +5,57 @@ import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ann.ModifyArgMixinData; +import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameter; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.config.PropertyKey; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.fixes.TypeAdapter; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; +import java.util.Set; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.INDEX; -public class ModifyArgMixin implements MixinType { +public class ModifyArgMixin implements MixinType { @Override public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } @Override - public ModifyArgMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { - Integer index = handle.getValue("index").map(AnnotationValueHandle::get).orElse(null); - return new ModifyArgMixinData(targetClass, targetMethod, atData, index); + public Set> requestProperties() { + return Set.of(Configuration.Keys.INDEX); } @Override - public void preProcess(ModifyArgMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ArbitraryInjectionPointSubResolver()); + public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + recipe.resolvers().getOrThrow(InjectionPointResolver.class) + .addSubResolver(new ArbitraryInjectionPointSubResolver()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY))); - mixin.index().ifPresent(i -> clean.setProperty(INDEX, i)); + + mixin.getProperty(INDEX) + .ifPresent(p -> clean.setProperty(INDEX, p)); + + return TxResult.SUCCESS; } @Override - public void postProcess(ModifyArgMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { if (clean.getAtData().equals(dirty.getAtData())) { dirty.inheritParameters(); dirty.inheritReturnType(); - return; + return TxResult.SUCCESS; } if (clean.hasProperty(INDEX) && !dirty.hasProperty(INDEX)) { @@ -59,10 +65,12 @@ public void postProcess(ModifyArgMixinData mixin, MixinContext context, Configur Type type = findArgType(context, recipe.clean().getAtData(), dirty.getAtData(), dirty); if (type != null) { MethodParameters parameters = MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY)); - parameters.set(SINGLE_ANY, List.of(type)); + parameters.set(SINGLE_ANY, Parameter.simple(type)); dirty.setParameters(parameters); dirty.setReturnType(type); } + + return TxResult.SUCCESS; } @Nullable @@ -70,8 +78,8 @@ private static Type findArgType(MixinContext context, AtData cleanAtData, AtData MethodQualifier cleanQualifier = cleanAtData.getTarget().flatMap(MethodQualifier::create).orElse(null); MethodQualifier dirtyQualifier = atData.getTarget().flatMap(MethodQualifier::create).orElse(null); if (cleanQualifier != null && dirtyQualifier != null) { - List cleanArgs = MethodParameters.getParameterTypes(cleanQualifier.desc()); - List dirtyArgs = MethodParameters.getParameterTypes(dirtyQualifier.desc()); + List cleanArgs = Parameters.getParameterTypes(cleanQualifier.desc()); + List dirtyArgs = Parameters.getParameterTypes(dirtyQualifier.desc()); if (dirty.hasProperty(INDEX)) { int dirtyIndex = dirty.getProperty(INDEX).orElseThrow(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java index d0e71fbf..1a306f79 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java @@ -3,65 +3,65 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ann.ModifyExpressionValueMixinData; +import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; +import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; +import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; -public class ModifyExpressionValueMixin implements MixinType { +public class ModifyExpressionValueMixin implements MixinType { @Override public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } @Override - public ModifyExpressionValueMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { - return new ModifyExpressionValueMixinData(targetClass, targetMethod, atData); - } - - @Override - public void preProcess(ModifyExpressionValueMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ArbitraryInjectionPointSubResolver()); recipe.resolvers().addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(true)); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, CAPTURED_PARAMS))); + + return TxResult.SUCCESS; } @Override - public void postProcess(ModifyExpressionValueMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - if (dirty.getTargetMethod() == null || dirty.getAtData() == null || !dirty.getAtData().getValue().equals(AT_VAL_INVOKE)) return; + public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + if (dirty.getTargetMethod() == null || dirty.getAtData() == null || !dirty.getAtData().getValue().equals(AT_VAL_INVOKE)) { + return TxResult.FAIL; + } MethodQualifier targetDesc = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); if (targetDesc == null) { // Best effort dirty.inheritParameters(); dirty.inheritReturnType(); - return; + return TxResult.SUCCESS; } List dirtyCaptured = context.methods().resolveCapturedMethodParams(recipe.clean(), recipe.dirty()); Type modifyingType = Type.getReturnType(targetDesc.desc()); MethodParameters params = MethodParameters.builder() - .put(SINGLE_ANY, modifyingType) - .put(CAPTURED_PARAMS, dirtyCaptured) + .putType(SINGLE_ANY, modifyingType) + .putTypes(CAPTURED_PARAMS, dirtyCaptured) .build(); dirty.setParameters(params); dirty.setReturnType(modifyingType); + + return TxResult.SUCCESS; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java index a0c8db1f..44230b6f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java @@ -3,78 +3,78 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ann.ModifyVariableMixinData; -import org.sinytra.adapter.next.env.ann.SliceData; +import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameter; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.config.PropertyKey; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.ModifyVarInjectionPointSubResolver; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.fixes.TypeAdapter; -import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; +import java.util.Set; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_ORDINAL; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_SLICE; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.LOCALS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; -import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.SLICE; -public class ModifyVariableMixin implements MixinType { +public class ModifyVariableMixin implements MixinType { @Override public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } @Override - public ModifyVariableMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { - boolean argsOnly = handle.getValue("argsOnly").map(AnnotationValueHandle::get).orElse(false); - Integer ordinal = handle.getValue(PROPERTY_ORDINAL).map(AnnotationValueHandle::get).orElse(null); - SliceData slice = handle.getNested(PROPERTY_SLICE) - .map(s -> SliceData.parse(s, context)) - .orElse(null); - return new ModifyVariableMixinData(targetClass, targetMethod, atData, argsOnly, ordinal, slice); + public Set> requestProperties() { + return Set.of(Keys.ARGS_ONLY, Keys.ORDINAL, Keys.SLICE); } @Override - public void preProcess(ModifyVariableMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + recipe.resolvers().getOrThrow(InjectionPointResolver.class) + .addSubResolver(new ModifyVarInjectionPointSubResolver()); + clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, LOCALS))); - clean.setProperty(SLICE, mixin.slice()); - recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ModifyVarInjectionPointSubResolver()); + mixin.getProperty(Keys.SLICE) + .ifPresent(p -> clean.setProperty(Keys.SLICE, p)); + + return TxResult.SUCCESS; } @Override - public void postProcess(ModifyVariableMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - dirty.inheritProperyIfAbsent(SLICE); + public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + dirty.inheritProperyIfAbsent(Keys.SLICE); - if (mixin.argsOnly() && dirty.getTargetMethod() != null && !dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { - Type cleanVarType = clean.getParameters().get(SINGLE_ANY).getFirst(); - List cleanTargetMethodParams = MethodParameters.getParameterTypes(clean.getTargetMethod().desc()); + boolean argsOnly = mixin.getProperty(Keys.ARGS_ONLY).orElse(false); + if (argsOnly && dirty.getTargetMethod() != null && !dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { + Type cleanVarType = clean.getParameters().getTypes(SINGLE_ANY).getFirst(); + List cleanTargetMethodParams = Parameters.getParameterTypes(clean.getTargetMethod().desc()); int cleanIndex = cleanTargetMethodParams.indexOf(cleanVarType); - List dirtyTargetMethodParams = MethodParameters.getParameterTypes(dirty.getTargetMethod().desc()); + List dirtyTargetMethodParams = Parameters.getParameterTypes(dirty.getTargetMethod().desc()); Type dirtyVarType = dirtyTargetMethodParams.get(cleanIndex); TypeAdapter adapter = context.getTypeAdapter(cleanVarType, dirtyVarType); if (adapter != null) { MethodParameters newParams = MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, LOCALS)); - newParams.get(SINGLE_ANY).set(0, dirtyVarType); + newParams.get(SINGLE_ANY).set(0, Parameter.simple(dirtyVarType)); dirty.setParameters(newParams); dirty.setReturnType(dirtyVarType); } - return; + return TxResult.SUCCESS; } dirty.inheritParameters(); dirty.inheritReturnType(); + + return TxResult.SUCCESS; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java index 95b418bd..778de60f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java @@ -3,12 +3,12 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; -import org.sinytra.adapter.next.env.ann.RedirectMixinData; +import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; @@ -16,7 +16,6 @@ import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; @@ -25,56 +24,58 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; -public class RedirectMixin implements MixinType { +public class RedirectMixin implements MixinType { @Override public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } @Override - public RedirectMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { - return new RedirectMixinData(targetClass, targetMethod, atData); - } - - @Override - public void preProcess(RedirectMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { recipe.resolvers().addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(false)); recipe.processors().addAfter(ParametersProcessor.class, new ParameterUsageProcessor()); if (clean.getAtData() == null || !MixinAnnotationConstants.AT_VAL_INVOKE.equals(clean.getAtData().getValue())) - return; + return TxResult.FAIL; MethodQualifier targetDesc = clean.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); - if (targetDesc == null) return; + if (targetDesc == null) + return TxResult.FAIL; - List callTypes = MethodParameters.getParameterTypes(targetDesc.desc()); - List methodTypes = MethodParameters.getParameterTypes(context.methodNode().desc); + List callTypes = Parameters.getParameterTypes(targetDesc.desc()); + List methodTypes = Parameters.getParameterTypes(context.methodNode().desc); List capturedMethodParams = new ArrayList<>(methodTypes.subList(callTypes.size(), methodTypes.size())); MethodParameters params = MethodParameters.builder() - .put(METHOD_PARAMS, callTypes) - .put(CAPTURED_PARAMS, capturedMethodParams) + .putTypes(METHOD_PARAMS, callTypes) + .putTypes(CAPTURED_PARAMS, capturedMethodParams) .build(); clean.setParameters(params); + + return TxResult.SUCCESS; } @Override - public void postProcess(RedirectMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - if (dirty.getTargetMethod() == null) return; + public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + if (dirty.getTargetMethod() == null) + return TxResult.FAIL; MethodQualifier targetDesc = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); - if (targetDesc == null) return; + if (targetDesc == null) + return TxResult.FAIL; List dirtyCaptured = context.methods().resolveCapturedMethodParams(recipe.clean(), recipe.dirty()); - List callTypes = MethodParameters.getParameterTypes(targetDesc.desc()); + List callTypes = Parameters.getParameterTypes(targetDesc.desc()); MethodParameters params = MethodParameters.builder() - .put(METHOD_PARAMS, callTypes) - .put(CAPTURED_PARAMS, dirtyCaptured) + .putTypes(METHOD_PARAMS, callTypes) + .putTypes(CAPTURED_PARAMS, dirtyCaptured) .build(); dirty.setParameters(params); dirty.setReturnType(Type.getReturnType(targetDesc.desc())); + + return TxResult.SUCCESS; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java index f8daa6ec..394913f8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java @@ -4,19 +4,21 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ann.WrapOperationMixinData; +import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.ctx.MethodHelper; import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; +import org.sinytra.adapter.next.pipeline.processor.wrapop.WrapOpParamsProcessor; import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; +import org.sinytra.adapter.next.pipeline.resolver.injection.ComparingInjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.api.MixinConstants; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; @@ -24,50 +26,58 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; -public class WrapOperationMixin implements MixinType { - @Override - public PropertyContainerTemplate getConfigurationTemplate() { - return ConfigurationTemplates.MIXIN_AT; - } +public class WrapOperationMixin implements MixinType { + private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_BASE.extend() + .requireOne(Configuration.Keys.TARGET_AT, Configuration.Keys.TARGET_CONSTANT) + .build(); @Override - public WrapOperationMixinData parse(MixinContext context, ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, AnnotationHandle handle) { - return new WrapOperationMixinData(targetClass, targetMethod, atData); + public PropertyContainerTemplate getConfigurationTemplate() { + return TEMPLATE; } @Override - public void preProcess(WrapOperationMixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { + public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { recipe.resolvers().getOrThrow(InjectionPointResolver.class) + .addSubResolverFirst(new ComparingInjectionPointResolver.WrapOperation()) .addSubResolver(new AtVariableAssignStoreSubResolver()); + recipe.processors() + .addAfter(ParametersProcessor.class, new WrapOpParamsProcessor()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(METHOD_PARAMS, OPERATION, CAPTURED_PARAMS, LOCALS))); + + return TxResult.SUCCESS; } @Override - public void postProcess(WrapOperationMixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - if (dirty.getTargetMethod() == null) return; + public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + if (dirty.getTargetMethod() == null) return TxResult.FAIL; + if (dirty.getAtData() == null) return TxResult.PASS; MethodQualifier dirtyAtTarget = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); - if (dirtyAtTarget == null) return; + if (dirtyAtTarget == null) + return TxResult.FAIL; List dirtyCaptured = context.methods().resolveCapturedMethodParams(recipe.clean(), recipe.dirty()); - List callTypes = new ArrayList<>(MethodParameters.getParameterTypes(dirtyAtTarget.desc())); + List callTypes = new ArrayList<>(Parameters.getParameterTypes(dirtyAtTarget.desc())); if (dirtyAtTarget.isFull()) { - MethodNode targetMethodCall = context.methods().findMethod(context.dirtyLookup(), dirtyAtTarget); + MethodNode targetMethodCall = context.methods().findInheritedMethod(context.dirtyLookup(), dirtyAtTarget); if (targetMethodCall != null && !MethodHelper.isStatic(targetMethodCall)) { callTypes.addFirst(Type.getObjectType(dirtyAtTarget.internalOwnerName())); } } MethodParameters params = MethodParameters.builder() - .put(METHOD_PARAMS, callTypes) - .put(OPERATION, AdapterUtil.OPERATION_TYPE) - .put(CAPTURED_PARAMS, dirtyCaptured) + .putTypes(METHOD_PARAMS, callTypes) + .putType(OPERATION, MixinConstants.OPERATION_TYPE) + .putTypes(CAPTURED_PARAMS, dirtyCaptured) .put(LOCALS, clean.getParameters().get(LOCALS)) .build(); dirty.setParameters(params); dirty.setReturnType(Type.getReturnType(dirtyAtTarget.desc())); + + return TxResult.SUCCESS; } } diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java index cbad5aa6..f5b8d54c 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java @@ -446,4 +446,39 @@ void testCompareReorderedParameters() { assertTrue(diff.removals().isEmpty()); assertEquals(1, diff.moves().size()); } + + @Test + void testCompareComplexChanges() { + List original = List.of( + Type.getType(String.class), + Type.getType(List.class) + ); + List modified = List.of( + Type.getType(Object.class) + ); + + LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(original, modified); + assertEquals(1, diff.replacements().size()); + assertEquals(Pair.of(0, Type.getType(Object.class)), diff.replacements().getFirst()); + assertEquals(1, diff.removals().size()); + assertEquals(1, diff.removals().getFirst()); + } + + @Test + void testRemovedParamsOrder() { + List original = List.of( + Type.getType(String.class), + Type.FLOAT_TYPE, + Type.FLOAT_TYPE, + Type.getType(Object.class), + Type.getType(List.class), + Type.INT_TYPE + ); + List modified = List.of( + Type.getType(String.class) + ); + + LayeredParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(original, modified); + assertEquals(List.of(1, 4, 3, 2, 1), diff.removals()); + } } 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 3dfc4aa3..853c3cf7 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 @@ -10,7 +10,7 @@ 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.transformer.dynamic.LocalCaptureUpgradePreprocessor; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.slf4j.Logger; import org.spongepowered.asm.mixin.FabricUtil; @@ -20,7 +20,7 @@ public class DynamicMixinPatchTest extends MinecraftMixinPatchTest { private static final List DYNAMIC_PATCHES = List.of( Patch.builder() - .transform(new DynamicInjectionPointPatch()) + .transform(new LocalCaptureUpgradePreprocessor()) .transform(new PipelineLegacyMethodTransformer()) .transform(new FieldTypeUsageTransformer()) .build() diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java index 5befaf44..1ac9ffcd 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java @@ -15,12 +15,24 @@ @Mixin(BoatRenderer.class) public class BoatRendererMixin { // https://github.com/TerraformersMC/Terraform/blob/0d569ebf8e6c78c79ccdb8b8f28c081089764aef/terraform-wood-api-v1/src/main/java/com/terraformersmc/terraform/boat/impl/mixin/MixinBoatEntityRenderer.java#L24 - @WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;")) + @WrapOperation( + method = "render", + at = @At( + value = "INVOKE", + target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;" + ) + ) private Object getBoatTextureAndModel(Map>> instance, Object type, Operation original, Boat entity) { return original.call(instance, type); } - @WrapOperation(method = "getModelWithLocation(Lnet/minecraft/world/entity/vehicle/Boat;)Lcom/mojang/datafixers/util/Pair;", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;")) + @WrapOperation( + method = "getModelWithLocation(Lnet/minecraft/world/entity/vehicle/Boat;)Lcom/mojang/datafixers/util/Pair;", + at = @At( + value = "INVOKE", + target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;" + ) + ) private Object getBoatTextureAndModelExpected(Map>> instance, Object type, Operation original, Boat entity) { return original.call(instance, type); } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PiglinAiMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PiglinAiMixin.java index 6cf50ad7..1c7efbac 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PiglinAiMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PiglinAiMixin.java @@ -15,12 +15,24 @@ @Mixin(PiglinAi.class) public class PiglinAiMixin { // https://github.com/quiqueck/BetterNether/blob/e1c5bea37001728844d16feec3ef3b3f14ae5139/src/main/java/org/betterx/betternether/mixin/common/piglin/PiglinAiMixin.java - @WrapOperation(method = "isWearingGold", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/Holder;is(Lnet/minecraft/core/Holder;)Z")) + @WrapOperation( + method = "isWearingGold(Lnet/minecraft/world/entity/LivingEntity;)Z", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/core/Holder;is(Lnet/minecraft/core/Holder;)Z" + ) + ) private static boolean isWearingGold(Holder instance, Holder tHolder, Operation original) { return original.call(instance, tHolder) || instance.is(ArmorMaterials.DIAMOND); } - @WrapOperation(method = "isWearingGold", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;makesPiglinsNeutral(Lnet/minecraft/world/entity/LivingEntity;)Z")) + @WrapOperation( + method = "isWearingGold(Lnet/minecraft/world/entity/LivingEntity;)Z", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;makesPiglinsNeutral(Lnet/minecraft/world/entity/LivingEntity;)Z" + ) + ) private static boolean isWearingGoldExpected(ItemStack instance, LivingEntity tHolder, Operation original) { if (!(instance.getItem() instanceof ArmorItem)) { return original.call(instance, tHolder); diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PumpkinBlockMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PumpkinBlockMixin.java index d2c88620..fa4407f0 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PumpkinBlockMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/PumpkinBlockMixin.java @@ -13,12 +13,24 @@ @Mixin(PumpkinBlock.class) public class PumpkinBlockMixin { // https://github.com/quiqueck/BCLib/blob/53349085e5d3adb20a023f29d9aab85acce58332/src/main/java/org/betterx/bclib/mixin/common/shears/PumpkinBlockMixin.java#L17 - @WrapOperation(method = "useItemOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z")) + @WrapOperation( + method = "useItemOn(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/ItemInteractionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z" + ) + ) private boolean isShears(ItemStack instance, Item item, Operation original) { return original.call(instance, item) || item == Items.SHEARS && !instance.isEmpty(); } - @WrapOperation(method = "useItemOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;canPerformAction(Lnet/neoforged/neoforge/common/ItemAbility;)Z")) + @WrapOperation( + method = "useItemOn(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/ItemInteractionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;canPerformAction(Lnet/neoforged/neoforge/common/ItemAbility;)Z" + ) + ) private boolean isShearsExpected(ItemStack instance, ItemAbility item, Operation original) { return original.call(instance, item) || instance.getItem() == Items.SHEARS && !instance.isEmpty(); } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/StemBlockMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/StemBlockMixin.java index 0e84914c..a9865fd2 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/StemBlockMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/StemBlockMixin.java @@ -29,7 +29,7 @@ private static boolean isOnFarmland(BlockState instance, Block block, Operation< method = "randomTick(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/util/RandomSource;)V", constant = @Constant(classValue = FarmBlock.class) ) - private static boolean isOnFarmlandExpected(Object instance, Operation original, @Local(ordinal = 1) BlockState adapter_injected_3) { - return Blocks.FARMLAND.equals(instance) || adapter_injected_3.isAir() || original.call(instance); + private static boolean isOnFarmlandExpected(Object instance, Operation original, @Local(ordinal = 1) BlockState adapter_injected_2) { + return Blocks.FARMLAND.equals(instance) || adapter_injected_2.isAir() || original.call(instance); } } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/TripWireBlockMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/TripWireBlockMixin.java index 7815879e..0e56e486 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/TripWireBlockMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/TripWireBlockMixin.java @@ -13,12 +13,24 @@ @Mixin(TripWireBlock.class) public class TripWireBlockMixin { // https://github.com/quiqueck/BCLib/blob/53349085e5d3adb20a023f29d9aab85acce58332/src/main/java/org/betterx/bclib/mixin/common/shears/TripWireBlockMixin.java#L17 - @WrapOperation(method = "playerWillDestroy", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z")) + @WrapOperation( + method = "playerWillDestroy(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/entity/player/Player;)Lnet/minecraft/world/level/block/state/BlockState;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z" + ) + ) private boolean isShears(ItemStack instance, Item item, Operation original) { return original.call(instance, item) || item == Items.SHEARS && instance.isEmpty(); } - @WrapOperation(method = "playerWillDestroy", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;canPerformAction(Lnet/neoforged/neoforge/common/ItemAbility;)Z")) + @WrapOperation( + method = "playerWillDestroy(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/entity/player/Player;)Lnet/minecraft/world/level/block/state/BlockState;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/ItemStack;canPerformAction(Lnet/neoforged/neoforge/common/ItemAbility;)Z" + ) + ) private boolean isShearsExpected(ItemStack instance, ItemAbility item, Operation original) { return original.call(instance, item) || instance.getItem() == Items.SHEARS && instance.isEmpty(); } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/CropBlockMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/CropBlockMixin.java index ce634f6d..c778ec80 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/CropBlockMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/CropBlockMixin.java @@ -14,10 +14,10 @@ public class CropBlockMixin { @WrapOperation( method = "getGrowthSpeed(Lnet/minecraft/world/level/block/Block;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)F", - at = {@At( + at = @At( value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z" - )} + ) ) private static boolean isOnFarmland(BlockState instance, Block block, Operation original) { return Blocks.FARMLAND.equals(block) || original.call(instance, block); @@ -25,10 +25,10 @@ private static boolean isOnFarmland(BlockState instance, Block block, Operation< @WrapOperation( method = "getGrowthSpeed(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)F", - at = {@At( + at = @At( value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z" - )} + ) ) private static boolean isOnFarmlandExpected(BlockState instance, Block block, Operation original) { return Blocks.FARMLAND.equals(block) || original.call(instance, block); From 66bd633c6fd7fc3bd5122e4a3f88c743ee075dd1 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Fri, 23 Jan 2026 19:01:15 +0100 Subject: [PATCH 06/27] New Patch pipeline and transformer itf --- .../adapter/patch/ClassPatchInstance.java | 134 ------------ .../adapter/patch/InterfacePatchInstance.java | 80 ------- .../adapter/patch/MethodContextImpl.java | 77 +------ .../adapter/patch/PatchAuditTrailImpl.java | 2 +- .../sinytra/adapter/patch/PatchInstance.java | 200 ------------------ .../patch/analysis/InheritanceHandler.java | 2 - .../analysis/locals/LocalVarAnalyzer.java | 10 +- .../params/LayeredParamsDiffSnapshot.java | 5 +- .../analysis/params/ParamsDiffSnapshot.java | 9 +- .../analysis/selector/AnnotationHandle.java | 1 + .../adapter/patch/api/ClassTransform.java | 10 - .../adapter/patch/api/LocalVariable.java | 6 + .../adapter/patch/api/MethodContext.java | 31 +-- .../adapter/patch/api/MethodTransform.java | 19 -- .../patch/api/MethodTransformBuilder.java | 40 ---- .../org/sinytra/adapter/patch/api/Patch.java | 88 -------- .../adapter/patch/api/PatchResult.java | 17 ++ .../sinytra/adapter/patch/api/TargetPair.java | 7 + .../fixes/FieldTypeUsageTransformer.java | 15 +- .../ModifyVarUpgradeToModifyExprVal.java | 93 -------- .../DynamicInheritedInjectionPointPatch.java | 66 ------ .../DynamicModifyVarAtReturnPatch.java | 153 -------------- .../LocalCaptureUpgradePreprocessor.java | 90 -------- .../param/InjectParameterTransform.java | 16 +- .../param/InlineParameterTransformer.java | 10 +- .../param}/ModifyArgsOffsetUpgrader.java | 2 +- .../param/MoveParametersTransformer.java | 8 +- .../operation/param/ParamTransformTarget.java | 35 --- .../operation/param/ParameterTransformer.java | 4 +- .../param/RemoveParameterTransformer.java | 6 +- .../param/ReplaceParametersTransformer.java | 15 +- .../param/SubstituteParameterTransformer.java | 8 +- .../param/SwapParametersTransformer.java | 8 +- .../operation/param/TransformParameters.java | 49 ++--- .../operation/unit/DisableMixin.java | 19 -- .../unit/DivertRedirectorTransform.java | 54 ----- .../operation/unit/ModifyInjectionPoint.java | 36 ---- .../operation/unit/ModifyInjectionTarget.java | 34 --- .../operation/unit/ModifyMethodAccess.java | 63 ------ .../operation/unit/ModifyMixinType.java | 75 ------- .../operation/unit/ModifyTargetClasses.java | 32 --- .../adapter/patch/util/AdapterUtil.java | 8 +- .../util/MethodTransformBuilderImpl.java | 74 ------- .../adapter/patch/util/MockMixinRuntime.java | 4 +- .../next/PipelineLegacyMethodTransformer.java | 61 ------ .../next/env/ConfigurationTemplates.java | 3 +- .../adapter/next/env/MixinContext.java | 44 +++- .../adapter/next/env/OrderedRegistry.java | 20 +- .../sinytra/adapter/next/env/ann/AtData.java | 136 ++++++++---- .../adapter/next/env/ann/ClassTarget.java | 40 +++- .../adapter/next/env/ann/ConstantData.java | 33 ++- .../env/ann/MixinAnnotationConstants.java | 5 + .../adapter/next/env/ann/MixinData.java | 42 ---- .../sinytra/adapter/next/env/ctx/Auditor.java | 5 + .../adapter/next/env/ctx/MethodFinder.java | 2 +- .../adapter/next/env/ctx/MethodHelper.java | 15 +- .../adapter/next/env/param/Parameter.java | 6 + .../adapter/next/env/param/Parameters.java | 3 +- .../adapter/next/flow/DynamicPatches.java | 33 +++ .../adapter/next/flow/MixinParser.java | 103 +++++++++ .../sinytra/adapter/next/flow/Patcher.java | 137 ++++++++++++ .../next/pipeline/PipelineExecutor.java | 166 --------------- .../pipeline/PipelineMethodTransformer.java | 130 ++++++++++++ .../sinytra/adapter/next/pipeline/Recipe.java | 12 +- .../next/pipeline/TxResultInstance.java | 35 --- .../config/BasePropertyContainer.java | 60 ++++-- .../next/pipeline/config/Configuration.java | 53 +---- .../pipeline/config/ConfigurationImpl.java | 23 +- .../adapter/next/pipeline/config/Keys.java | 80 +++++++ .../config/MutablePropertyContainer.java | 15 ++ .../config/PropertyContainerTemplate.java | 27 ++- .../next/pipeline/config/PropertyKey.java | 64 ++++-- .../next/pipeline/config/SpecialKeys.java | 16 ++ .../processor/DisableMixinProcessor.java | 4 +- .../processor/InjectionTargetProcessor.java | 7 +- .../processor/MixinTypeProcessor.java | 7 +- .../processor/ParametersProcessor.java | 10 +- .../next/pipeline/processor/Processor.java | 3 +- .../next/pipeline/processor/Processors.java | 1 + .../pipeline/processor/PropertyProcessor.java | 7 +- .../processor/ReturnTypeProcessor.java | 3 +- .../processor/StaticAccessProcessor.java | 62 ++++++ .../processor/TargetMethodProcessor.java | 6 +- .../processor/extract}/ExtractMixin.java | 68 +++--- .../extract/ExtractMixinProcessor.java | 15 +- .../extract/MirrorableExtractMixin.java | 31 +-- .../redirect/DivertRedirectProcessor.java | 57 +++++ .../ParameterUsageProcessor.java | 6 +- .../processor/wrapop/WrapOpAnalyzer.java | 5 +- .../wrapop/WrapOpParamsProcessor.java | 3 +- .../pipeline/resolver/CompoundResolver.java | 9 +- .../next/pipeline/resolver/Resolver.java | 3 +- .../next/pipeline/resolver/Resolvers.java | 8 +- .../next/pipeline/resolver/SubResolver.java | 3 +- .../ArbitraryInjectionPointSubResolver.java | 13 +- .../AtVariableAssignStoreSubResolver.java | 9 +- .../ComparingInjectionPointResolver.java | 35 +-- .../InheritedInjectionPointSubResolver.java | 85 ++++++++ .../injection/InjectionPointResolver.java | 10 +- .../injection/InjectionPointSubResolvers.java | 11 +- .../ModifyVarInjectionPointSubResolver.java | 17 +- .../special/InjectorOrdinalResolver.java} | 177 +++++++++------- .../special/ModifyVarAtReturnResolver.java | 147 +++++++++++++ .../special/ModifyVarUpgradeResolver.java | 95 +++++++++ .../special/ResolverSyntheticInstanceof.java | 18 +- .../special/SliceBoundaryResolver.java | 11 +- .../target/SplitMethodCancellationHelper.java | 6 +- .../target/SplitTargetMethodSubResolver.java | 28 +-- .../resolver/target/TargetMethodResolver.java | 13 +- .../target/TargetMethodSubResolvers.java | 23 +- .../next/transform/ClassTransformer.java | 10 + .../FieldAccessorTypeTransformer.java} | 64 +++--- .../next/transform/MethodTransformer.java | 9 + .../cls}/DynamicAnonClassIndexPatch.java | 49 ++--- .../DynamicAnonymousShadowFieldTypePatch.java | 39 ++-- .../transform/patch/ConfigurationMatcher.java | 46 ++++ .../next/transform/patch/MethodPatch.java | 18 ++ .../transform/patch/MethodPatchBuilder.java | 46 ++++ .../patch/MethodPatchBuilderImpl.java | 139 ++++++++++++ .../next/transform/patch/MethodPatchImpl.java | 33 +++ .../patch/MethodPatchTransformer.java | 67 ++++++ .../CapturedLocalsPreProcessor.java} | 64 +++--- .../LocalCaptureUpgradeTransformer.java | 72 +++++++ .../adapter/next/type/InjectMixin.java | 46 ++-- .../sinytra/adapter/next/type/MixinType.java | 16 +- .../sinytra/adapter/next/type/MixinTypes.java | 24 ++- .../adapter/next/type/ModifyArgMixin.java | 32 ++- .../next/type/ModifyExpressionValueMixin.java | 15 +- .../next/type/ModifyReturnValueMixin.java | 32 +++ .../next/type/ModifyVariableMixin.java | 38 ++-- .../adapter/next/type/RedirectMixin.java | 19 +- .../adapter/next/type/WrapOperationMixin.java | 16 +- .../patch/test/ParameterComparisonTest.java | 4 +- .../test/mixin/DynamicMixinPatchTest.java | 23 +- 134 files changed, 2460 insertions(+), 2561 deletions(-) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/InterfacePatchInstance.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/PatchInstance.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/ClassTransform.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/LocalVariable.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransform.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/Patch.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/PatchResult.java create mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/TargetPair.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyVarUpgradeToModifyExprVal.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/LocalCaptureUpgradePreprocessor.java rename definition/src/main/java/org/sinytra/adapter/patch/transformer/{ => operation/param}/ModifyArgsOffsetUpgrader.java (96%) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformTarget.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DisableMixin.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DivertRedirectorTransform.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMethodAccess.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMixinType.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyTargetClasses.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/ctx/Auditor.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/TxResultInstance.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/SpecialKeys.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/StaticAccessProcessor.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation/unit => next/java/org/sinytra/adapter/next/pipeline/processor/extract}/ExtractMixin.java (86%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java rename definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/{ => redirect}/ParameterUsageProcessor.java (86%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java => next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java} (70%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java rename definition/src/{main/java/org/sinytra/adapter/patch/fixes/FieldTypePatchTransformer.java => next/java/org/sinytra/adapter/next/transform/FieldAccessorTypeTransformer.java} (63%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/dynamic => next/java/org/sinytra/adapter/next/transform/cls}/DynamicAnonClassIndexPatch.java (67%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/dynamic => next/java/org/sinytra/adapter/next/transform/cls}/DynamicAnonymousShadowFieldTypePatch.java (64%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/patch/ConfigurationMatcher.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatch.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilder.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchImpl.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java => next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java} (80%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java create mode 100644 definition/src/next/java/org/sinytra/adapter/next/type/ModifyReturnValueMixin.java diff --git a/definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java b/definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java deleted file mode 100644 index 99eb92df..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/ClassPatchInstance.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.sinytra.adapter.patch; - -import org.objectweb.asm.commons.InstructionAdapter; -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.analysis.selector.InjectionPointMatcher; -import org.sinytra.adapter.patch.analysis.selector.MethodMatcher; -import org.sinytra.adapter.patch.api.ClassTransform; -import org.sinytra.adapter.patch.api.MethodTransform; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import org.sinytra.adapter.patch.transformer.operation.unit.DisableMixin; -import org.sinytra.adapter.patch.transformer.operation.unit.DivertRedirectorTransform; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionPoint; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public final class ClassPatchInstance extends PatchInstance { - private final List targetMethods; - private final List targetInjectionPoints; - - private ClassPatchInstance(List targetClasses, List targetMethods, List targetInjectionPoints, List targetAnnotations, Predicate targetAnnotationValues, List classTransforms, List transforms) { - super(targetClasses, targetAnnotations, targetAnnotationValues, classTransforms, transforms); - - this.targetMethods = targetMethods; - this.targetInjectionPoints = targetInjectionPoints; - } - - @Override - protected boolean checkAnnotation(String owner, MethodNode method, AnnotationHandle methodAnnotation, PatchEnvironment remaper, MethodContextImpl.Builder builder) { - builder.methodNode(method); - builder.methodAnnotation(methodAnnotation); - if (methodAnnotation.matchesDesc(MixinConstants.OVERWRITE)) { - return this.targetMethods.isEmpty() || this.targetMethods.stream().anyMatch(matcher -> matcher.matches(method.name, method.desc)); - } else if (KNOWN_MIXIN_TYPES.contains(methodAnnotation.getDesc())) { - return methodAnnotation.>getValue("method") - .map(value -> { - List matchingTargets = new ArrayList<>(); - for (String target : value.get()) { - String remappedTarget = remaper.refmapHolder().remap(owner, target); - MethodQualifier qualifier = MethodQualifier.create(remappedTarget).filter(q -> q.name() != null).orElse(null); - if (qualifier == null) { - continue; - } - String targetName = qualifier.name(); - String targetDesc = qualifier.desc(); - if ((this.targetMethods.isEmpty() || this.targetMethods.stream().anyMatch(matcher -> matcher.matches(targetName, targetDesc))) - // Must call checkInjectionPoint first so that any present @At annotation is added to the method context builder - && checkInjectionPoint(owner, methodAnnotation, remaper, builder) - ) { - matchingTargets.add(target); - } - } - builder.matchingTargets(matchingTargets); - return !matchingTargets.isEmpty(); - }) - .orElse(false); - } - return false; - } - - private boolean checkInjectionPoint(String owner, AnnotationHandle methodAnnotation, PatchEnvironment environment, MethodContextImpl.Builder builder) { - return methodAnnotation.getNested("at") - .flatMap(node -> checkInjectionPointAnnotation(owner, node, environment, builder)) - // Check slice.from target - .or(() -> methodAnnotation.getValue("slice") - .flatMap(slice -> slice.findNested("from") - .flatMap(from -> checkInjectionPointAnnotation(owner, from, environment, builder)))) - .orElse(this.targetInjectionPoints.isEmpty()); - } - - private Optional checkInjectionPointAnnotation(String owner, AnnotationHandle injectionPointAnnotation, PatchEnvironment environment, MethodContextImpl.Builder builder) { - AnnotationValueHandle value = injectionPointAnnotation.getValue("value").orElse(null); - String valueStr = value != null ? value.get() : null; - String targetStr = injectionPointAnnotation.getValue("target").map(t -> environment.refmapHolder().remap(owner, t.get())).orElse(""); - if (this.targetInjectionPoints.isEmpty() || this.targetInjectionPoints.stream().anyMatch(pred -> pred.test(valueStr, targetStr))) { - builder.injectionPointAnnotation(injectionPointAnnotation); - return Optional.of(true); - } - return Optional.empty(); - } - - public static class ClassPatchBuilderImpl extends BaseBuilder implements ClassPatchBuilder { - private final Set targetMethods = new HashSet<>(); - private final Set targetInjectionPoints = new HashSet<>(); - - @Override - public ClassPatchBuilder targetMethod(String... targets) { - for (String target : targets) { - this.targetMethods.add(new MethodMatcher(target)); - } - return this; - } - - @Override - public ClassPatchBuilder targetInjectionPoint(String value, String target) { - this.targetInjectionPoints.add(new InjectionPointMatcher(value, target)); - return this; - } - - @Override - public ClassPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues) { - return transform(new ModifyInjectionPoint(value, target, resetValues)); - } - - @Override - public ClassPatchBuilder divertRedirector(Consumer patcher) { - return transform(new DivertRedirectorTransform(patcher)); - } - - @Override - public ClassPatchBuilder disable() { - return transform(DisableMixin.INSTANCE); - } - - @Override - public PatchInstance build() { - return new ClassPatchInstance( - List.copyOf(this.targetClasses), - List.copyOf(this.targetMethods), - List.copyOf(this.targetInjectionPoints), - List.copyOf(this.targetAnnotations), - this.targetAnnotationValues, - List.copyOf(this.classTransforms), - List.copyOf(this.transforms) - ); - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/InterfacePatchInstance.java b/definition/src/main/java/org/sinytra/adapter/patch/InterfacePatchInstance.java deleted file mode 100644 index 55e86ad1..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/InterfacePatchInstance.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.sinytra.adapter.patch; - -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.FieldMatcher; -import org.sinytra.adapter.patch.api.ClassTransform; -import org.sinytra.adapter.patch.api.MethodTransform; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import org.sinytra.adapter.patch.util.AdapterUtil; - -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -public final class InterfacePatchInstance extends PatchInstance { - public static final Collection KNOWN_INTERFACE_MIXIN_TYPES = Set.of(MixinConstants.ACCESSOR); - - private final List targetFields; - - private InterfacePatchInstance(List targetClasses, List targetFields, List targetAnnotations, Predicate targetAnnotationValues, List classTransforms, List transforms) { - super(targetClasses, targetAnnotations, targetAnnotationValues, classTransforms, transforms); - - this.targetFields = targetFields; - } - - @Override - public Result apply(ClassNode classNode, PatchEnvironment environment) { - if ((classNode.access & Opcodes.ACC_INTERFACE) == 0) { - return Result.PASS; - } - return super.apply(classNode, environment); - } - - @Override - protected boolean checkAnnotation(String owner, MethodNode method, AnnotationHandle methodAnnotation, PatchEnvironment environment, MethodContextImpl.Builder builder) { - if (KNOWN_INTERFACE_MIXIN_TYPES.contains(methodAnnotation.getDesc())) { - // Find accessor target - if (methodAnnotation.matchesDesc(MixinConstants.ACCESSOR)) { - FieldMatcher matcher = AdapterUtil.getAccessorTargetFieldName(owner, method, methodAnnotation, environment) - .map(FieldMatcher::new) - .orElse(null); - if (matcher != null && (this.targetFields.isEmpty() || this.targetFields.stream().anyMatch(m -> m.matches(matcher)))) { - builder.methodNode(method); - builder.methodAnnotation(methodAnnotation); - return true; - } - } - } - return false; - } - - public static class InterfaceClassPatchBuilderImpl extends BaseBuilder implements InterfacePatchBuilder { - private final Set targetFields = new HashSet<>(); - - @Override - public InterfacePatchBuilder targetField(String... targets) { - for (String target : targets) { - this.targetFields.add(new FieldMatcher(target)); - } - return this; - } - - @Override - public PatchInstance build() { - return new InterfacePatchInstance( - List.copyOf(this.targetClasses), - List.copyOf(this.targetFields), - List.copyOf(this.targetAnnotations), - this.targetAnnotationValues, - List.copyOf(this.classTransforms), - List.copyOf(this.transforms) - ); - } - } -} 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 c9022d53..c3eb3df1 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java @@ -10,10 +10,7 @@ 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; -import org.sinytra.adapter.patch.api.MethodTransform; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.*; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.MockMixinRuntime; @@ -41,7 +38,6 @@ public final class MethodContextImpl implements MethodContext { private final AnnotationHandle methodAnnotation; private final @Nullable AnnotationHandle injectionPointAnnotation; private final List targetTypes; - private final List matchingTargets; private final PatchContext patchContext; private final Supplier cleanInjectionPairCache; @@ -50,7 +46,7 @@ public final class MethodContextImpl implements MethodContext { private final Supplier dirtyLocalsTableCache; private final Map> targetInstructionsCache; - public MethodContextImpl(ClassNode classNode, AnnotationHandle rawClassAnnotation, AnnotationValueHandle classAnnotation, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation, List targetTypes, List matchingTargets, PatchContext patchContext) { + public MethodContextImpl(ClassNode classNode, AnnotationHandle rawClassAnnotation, AnnotationValueHandle classAnnotation, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation, List targetTypes, PatchContext patchContext) { this.classNode = Objects.requireNonNull(classNode, "Missing class node"); this.rawClassAnnotation = Objects.requireNonNull(rawClassAnnotation, "Missing raw class annotation"); this.classAnnotation = Objects.requireNonNull(classAnnotation, "Missing class annotation"); @@ -58,7 +54,6 @@ public MethodContextImpl(ClassNode classNode, AnnotationHandle rawClassAnnotatio this.methodAnnotation = Objects.requireNonNull(methodAnnotation, "Missing method annotation"); this.injectionPointAnnotation = injectionPointAnnotation; this.targetTypes = Objects.requireNonNull(targetTypes, "Missing target types"); - this.matchingTargets = Objects.requireNonNull(matchingTargets, "Missing matching targets"); this.patchContext = patchContext; this.cleanInjectionPairCache = Suppliers.memoize(() -> { @@ -71,11 +66,6 @@ public MethodContextImpl(ClassNode classNode, AnnotationHandle rawClassAnnotatio this.dirtyLocalsTableCache = Suppliers.memoize(() -> Optional.ofNullable(findDirtyInjectionTarget()).map(pair -> new LocalVariableLookup(pair.methodNode())).orElse(null)); } - @Override - public AnnotationHandle injectionPointAnnotationOrThrow() { - return Objects.requireNonNull(this.injectionPointAnnotation, "Missing injection point annotation"); - } - @Override public TargetPair findCleanInjectionTarget() { return this.cleanInjectionPairCache.get(); @@ -111,30 +101,16 @@ public MethodQualifier getTargetMethodQualifier() { return MethodQualifier.create(reference).orElse(null); } - @Nullable - @Override - public MethodQualifier getInjectionPointMethodQualifier() { - // Get injection target - String target = injectionPointAnnotation().getValue("target").map(AnnotationValueHandle::get).orElse(null); - if (target == null) { - return null; - } - // Resolve method reference - String reference = patchContext().remap(target); - // Extract owner, name and desc using regex - return MethodQualifier.create(reference).orElse(null); - } - @Override public List findInjectionTargetInsns(@Nullable TargetPair target) { return this.targetInstructionsCache.computeIfAbsent(target, this::computeInjectionTargetInsns); } @Override - public void updateDescription(MethodTransform transform, List parameters) { + public void updateDescription(List parameters) { Type returnType = Type.getReturnType(this.methodNode.desc); String newDesc = Type.getMethodDescriptor(returnType, parameters.toArray(Type[]::new)); - recordAudit(transform, "Change descriptor to %s", newDesc); +// recordAudit(transform, "Change descriptor to %s", newDesc); this.methodNode.desc = newDesc; this.methodNode.signature = null; } @@ -144,11 +120,6 @@ public boolean isStatic() { return (this.methodNode.access & Opcodes.ACC_STATIC) != 0; } - @Override - public boolean isCancellable() { - return methodAnnotation().matchesDesc(MixinConstants.INJECT) && methodAnnotation().getValue("cancellable").map(AnnotationValueHandle::get).orElse(false); - } - @Nullable @Override public List getTargetMethodLocals(TargetPair target) { @@ -228,22 +199,12 @@ public List getLvtCompatLevelsOrdered() { .toList(); } - @Override - public boolean capturesLocals() { - return methodAnnotation().getValue("locals").isPresent(); - } - @Override public boolean failsDirtyInjectionCheck() { TargetPair dirtyPair = findDirtyInjectionTarget(); return dirtyPair == null || computeInjectionTargetInsns(dirtyPair).isEmpty() && computeConstantTargetInsns(dirtyPair).isEmpty(); } - @Override - public boolean hasInjectionPointValue(String value) { - return this.injectionPointAnnotation != null && this.injectionPointAnnotation.getValue("value").map(v -> value.equals(v.get())).orElse(false); - } - @Override public boolean isNotRequired() { return this.methodAnnotation.getValue("require") @@ -337,7 +298,7 @@ public Pair> findInjectionTargetCandidates(ClassLook } String owner = Optional.ofNullable(qualifier.internalOwnerName()) .orElseGet(() -> { - List targetTypes = targetTypes(); + List targetTypes = this.targetTypes; if (targetTypes.size() == 1) { return targetTypes.getFirst().getInternalName(); } @@ -377,16 +338,6 @@ public MethodNode getMixinMethod() { return this.methodNode; } - @Override - public AnnotationHandle rawClassAnnotation() { - return this.rawClassAnnotation; - } - - @Override - public AnnotationValueHandle classAnnotation() { - return this.classAnnotation; - } - @Override public AnnotationHandle methodAnnotation() { return this.methodAnnotation; @@ -398,16 +349,6 @@ public AnnotationHandle injectionPointAnnotation() { return this.injectionPointAnnotation; } - @Override - public List targetTypes() { - return this.targetTypes; - } - - @Override - public List matchingTargets() { - return this.matchingTargets; - } - @Override public PatchContext patchContext() { return this.patchContext; @@ -421,7 +362,6 @@ public static class Builder { private AnnotationHandle methodAnnotation; private AnnotationHandle injectionPointAnnotation; private final List targetTypes = new ArrayList<>(); - private final List matchingTargets = new ArrayList<>(); public Builder classNode(ClassNode classNode) { this.classNode = classNode; @@ -458,13 +398,8 @@ public Builder targetTypes(List targetTypes) { return this; } - public Builder matchingTargets(List matchingTargets) { - this.matchingTargets.addAll(matchingTargets); - return this; - } - public MethodContextImpl build(PatchContext context) { - return new MethodContextImpl(this.classNode, this.rawClassAnnotation, this.classAnnotation, this.methodNode, this.methodAnnotation, this.injectionPointAnnotation, List.copyOf(this.targetTypes), List.copyOf(this.matchingTargets), context); + return new MethodContextImpl(this.classNode, this.rawClassAnnotation, this.classAnnotation, this.methodNode, this.methodAnnotation, this.injectionPointAnnotation, List.copyOf(this.targetTypes), context); } } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java b/definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java index f1075727..4dbc97e4 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java @@ -13,7 +13,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; public class PatchAuditTrailImpl implements PatchAuditTrail { private static final DecimalFormat FORMAT = new DecimalFormat("##.00"); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/PatchInstance.java b/definition/src/main/java/org/sinytra/adapter/patch/PatchInstance.java deleted file mode 100644 index bb801d13..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/PatchInstance.java +++ /dev/null @@ -1,200 +0,0 @@ -package org.sinytra.adapter.patch; - -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.MethodNode; -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.transformer.operation.unit.ModifyTargetClasses; -import org.sinytra.adapter.patch.util.MethodTransformBuilderImpl; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public abstract sealed class PatchInstance implements Patch permits ClassPatchInstance, InterfacePatchInstance { - public static final Collection KNOWN_MIXIN_TYPES = Set.of( - MixinConstants.INJECT, MixinConstants.REDIRECT, MixinConstants.MODIFY_ARG, - MixinConstants.MODIFY_ARGS, MixinConstants.MODIFY_VAR, MixinConstants.MODIFY_CONST, - MixinConstants.MODIFY_EXPR_VAL, MixinConstants.WRAP_OPERATION, MixinConstants.WRAP_WITH_CONDITION, - MixinConstants.MODIFY_RETURN_VAL - ); - - public static final Marker MIXINPATCH = MarkerFactory.getMarker("MIXINPATCH"); - - protected final List targetClasses; - - protected final List targetAnnotations; - @Nullable - protected final Predicate targetAnnotationValues; - protected final List classTransforms; - protected final List transforms; - - protected PatchInstance(List targetClasses, List targetAnnotations, List transforms) { - this(targetClasses, targetAnnotations, map -> true, List.of(), transforms); - } - - protected PatchInstance(List targetClasses, List targetAnnotations, Predicate targetAnnotationValues, List classTransforms, List transforms) { - this.targetClasses = targetClasses; - this.targetAnnotations = targetAnnotations; - this.targetAnnotationValues = targetAnnotationValues; - this.classTransforms = classTransforms; - this.transforms = transforms; - } - - @Override - public Result apply(ClassNode classNode, PatchEnvironment environment) { - Result result = Result.PASS; - ClassTarget classTarget = checkClassTarget(classNode); - if (classTarget != null) { - PatchContextImpl context = new PatchContextImpl(classNode, classTarget.targetTypes(), environment); - AnnotationValueHandle classAnnotation = classTarget.handle(); - for (ClassTransform classTransform : this.classTransforms) { - result = result.or(classTransform.apply(classNode, classTarget.handle(), context)); - } - for (MethodNode method : classNode.methods) { - MethodContext methodContext = checkMethodTarget(classTarget.ann(), classAnnotation, classNode, method, environment, classTarget.targetTypes(), context); - if (methodContext != null) { - if (!this.transforms.isEmpty()) { - environment.auditTrail().prepareMethod(methodContext); - } - for (MethodTransform transform : this.transforms) { - Collection accepted = transform.getAcceptedAnnotations(); - if (accepted.isEmpty() || accepted.contains(methodContext.methodAnnotation().getDesc())) { - Patch.Result txResult = transform.apply(classNode, method, methodContext, context); - result = result.or(txResult); - if (txResult == Result.APPLY && environment.auditTrail().getMatch(methodContext) == PatchAuditTrail.Match.FULL) { - break; - } - } - } - } - } - context.run(); - } - return result; - } - - private ClassTarget checkClassTarget(ClassNode classNode) { - if (classNode.invisibleAnnotations != null) { - for (AnnotationNode annotation : classNode.invisibleAnnotations) { - if (annotation.desc.equals(MixinConstants.MIXIN)) { - AnnotationHandle ann = new AnnotationHandle(annotation); - - return PatchInstance.>findAnnotationValue(annotation.values, "value") - .map(types -> { - for (Type targetType : types.get()) { - if (this.targetClasses.isEmpty() || this.targetClasses.contains(targetType.getInternalName())) { - return new ClassTarget(ann, types, types.get()); - } - } - return null; - }) - .or(() -> PatchInstance.>findAnnotationValue(annotation.values, "targets") - .map(types -> { - for (String targetType : types.get()) { - if (this.targetClasses.isEmpty() || this.targetClasses.contains(targetType)) { - return new ClassTarget(ann, types, types.get().stream().map(Type::getObjectType).toList()); - } - } - return null; - })) - .orElse(null); - } - } - } - return this.targetClasses.isEmpty() ? new ClassTarget(null, null, List.of()) : null; - } - - @Nullable - private MethodContext checkMethodTarget(@Nullable AnnotationHandle rawClassAnnotation, @Nullable AnnotationValueHandle classAnnotation, ClassNode owner, MethodNode method, PatchEnvironment remaper, List targetTypes, PatchContext context) { - if (method.visibleAnnotations != null) { - for (AnnotationNode annotation : method.visibleAnnotations) { - if (this.targetAnnotations.isEmpty() || this.targetAnnotations.contains(annotation.desc)) { - MethodContextImpl.Builder builder = MethodContextImpl.builder(); - if (rawClassAnnotation != null && classAnnotation != null) { - builder.classNode(owner); - builder.rawClassAnnotation(rawClassAnnotation); - builder.classAnnotation(classAnnotation); - builder.targetTypes(targetTypes); - } - AnnotationHandle annotationHandle = new AnnotationHandle(annotation); - if (checkAnnotation(owner.name, method, annotationHandle, remaper, builder) && (this.targetAnnotationValues == null || this.targetAnnotationValues.test(annotationHandle))) { - return builder.build(context); - } - } - } - } - return null; - } - - protected abstract boolean checkAnnotation(String owner, MethodNode method, AnnotationHandle annotation, PatchEnvironment remaper, MethodContextImpl.Builder builder); - - public static Optional> findAnnotationValue(@Nullable List values, String key) { - if (values != null) { - for (int i = 0; i < values.size(); i += 2) { - String atKey = (String) values.get(i); - if (atKey.equals(key)) { - int index = i + 1; - return Optional.of(new AnnotationValueHandle<>(values, index, key)); - } - } - } - return Optional.empty(); - } - - private record ClassTarget(AnnotationHandle ann, @Nullable AnnotationValueHandle handle, List targetTypes) { - } - - protected abstract static class BaseBuilder> extends MethodTransformBuilderImpl implements Builder { - protected final Set targetClasses = new HashSet<>(); - protected final Set targetAnnotations = new HashSet<>(); - protected Predicate targetAnnotationValues; - protected final List classTransforms = new ArrayList<>(); - - @Override - public T targetClass(String... targets) { - this.targetClasses.addAll(List.of(targets)); - return coerce(); - } - - @Override - public T targetMixinType(String... annotationDescs) { - this.targetAnnotations.addAll(List.of(annotationDescs)); - return coerce(); - } - - @Override - public T targetAnnotationValues(Predicate values) { - this.targetAnnotationValues = this.targetAnnotationValues == null ? values : this.targetAnnotationValues.or(values); - return coerce(); - } - - @Override - public T modifyTargetClasses(Consumer> consumer) { - return transform(new ModifyTargetClasses(consumer)); - } - - @Override - public T transform(List classTransforms) { - this.classTransforms.addAll(classTransforms); - return coerce(); - } - - @Override - public T transform(ClassTransform transformer) { - this.classTransforms.add(transformer); - return coerce(); - } - - @SuppressWarnings("unchecked") - private T coerce() { - return (T) this; - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java index 9cb58862..af078fb1 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java @@ -1,8 +1,6 @@ package org.sinytra.adapter.patch.analysis; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.patch.util.provider.ClassLookup; import java.util.*; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java index 206548bd..8bee0f64 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java @@ -9,8 +9,8 @@ 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.LocalVariable; 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; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -32,11 +32,11 @@ public static CapturedLocalsInfo getCapturedLocals(MethodContext methodContext) return null; } // Get available local variables at the injection point in the target method - List available = methodContext.getTargetMethodLocals(capturedLocals.target()); + List available = methodContext.getTargetMethodLocals(capturedLocals.target()); if (available == null) { return null; } - List availableTypes = available.stream().map(MethodContext.LocalVariable::type).toList(); + List availableTypes = available.stream().map(LocalVariable::type).toList(); // Compare expected and available params ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(capturedLocals.expected(), availableTypes); return new CapturedLocalsInfo(capturedLocals, diff, availableTypes); @@ -63,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, List usedLocalNodes) { + public record CapturedLocalsTransform(List used, TransformParameters remover, List usedLocalNodes) { public CapturedLocalsUsage getUsage(AdapterUtil.CapturedLocals capturedLocals) { LocalVariableLookup targetTable = new LocalVariableLookup(capturedLocals.target().methodNode()); Int2ObjectMap varInsnLists = new Int2ObjectOpenHashMap<>(); @@ -96,7 +96,7 @@ public static CapturedLocalsTransform analyzeCapturedLocals(AdapterUtil.Captured } } // Remove unused captured locals - MethodTransform remover = TransformParameters.builder() + TransformParameters remover = TransformParameters.builder() .chain(b -> IntStream.range(paramLocalStart, capturedLocals.paramLocalEnd()) .filter(i -> !used.contains(i)) .boxed().sorted(Collections.reverseOrder()) diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java index 6dc84269..a97e7d44 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java @@ -5,7 +5,6 @@ import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.patch.api.MethodTransform; import org.sinytra.adapter.patch.transformer.operation.param.*; import java.util.ArrayList; @@ -229,9 +228,9 @@ public LayeredParamsDiffSnapshot offset(int offset, int limit) { } @Override - public MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset, Set flags) { + public TransformParameters asParameterTransformer(boolean withOffset, Set flags) { List transformers = this.modifications.stream().map(paramModification -> paramModification.asParameterTransformer(flags)).toList(); - return TransformParameters.builder().transform(transformers).withOffset(withOffset).targetType(type).build(); + return TransformParameters.builder().transform(transformers).withOffset(withOffset).build(); } public static Builder builder() { diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java index 25234bd8..53731ad7 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java @@ -3,8 +3,7 @@ import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.patch.api.MethodTransform; -import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformTarget; +import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; import java.util.EnumSet; import java.util.List; @@ -36,9 +35,9 @@ enum Flags { ParamsDiffSnapshot offset(int offset, int limit); - default MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset) { - return asParameterTransformer(type, withOffset, EnumSet.of(ParamsDiffSnapshot.Flags.REMOVED_VAR_GRAVE)); + default TransformParameters asParameterTransformer(boolean withOffset) { + return asParameterTransformer(withOffset, EnumSet.of(ParamsDiffSnapshot.Flags.REMOVED_VAR_GRAVE)); } - MethodTransform asParameterTransformer(ParamTransformTarget type, boolean withOffset, Set flags); + TransformParameters asParameterTransformer(boolean withOffset, Set flags); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java index e9c795d4..3466e7d5 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java @@ -17,6 +17,7 @@ public String getDesc() { return this.annotationNode.desc; } + // TODO Remove me public boolean matchesDesc(String desc) { return this.annotationNode.desc.equals(desc); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/ClassTransform.java b/definition/src/main/java/org/sinytra/adapter/patch/api/ClassTransform.java deleted file mode 100644 index d70cc834..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/ClassTransform.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sinytra.adapter.patch.api; - -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.api.Patch.Result; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; - -public interface ClassTransform { - Result apply(ClassNode classNode, @Nullable AnnotationValueHandle annotation, PatchContext context); -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/LocalVariable.java b/definition/src/main/java/org/sinytra/adapter/patch/api/LocalVariable.java new file mode 100644 index 00000000..9cb159c3 --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/api/LocalVariable.java @@ -0,0 +1,6 @@ +package org.sinytra.adapter.patch.api; + +import org.objectweb.asm.Type; + +public record LocalVariable(int index, Type type) { +} 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 4929d05f..8cf5a33f 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,33 +6,23 @@ import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.ctx.Auditor; 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; import org.sinytra.adapter.patch.util.provider.ClassLookup; import java.util.List; -public interface MethodContext { +public interface MethodContext extends Auditor { ClassNode getMixinClass(); MethodNode getMixinMethod(); - AnnotationHandle rawClassAnnotation(); - - AnnotationValueHandle classAnnotation(); - AnnotationHandle methodAnnotation(); @Nullable AnnotationHandle injectionPointAnnotation(); - AnnotationHandle injectionPointAnnotationOrThrow(); - - List targetTypes(); - - List matchingTargets(); - PatchContext patchContext(); TargetPair findCleanInjectionTarget(); @@ -46,9 +36,6 @@ public interface MethodContext { @Nullable MethodQualifier getTargetMethodQualifier(); - @Nullable - MethodQualifier getInjectionPointMethodQualifier(); - List findInjectionTargetInsns(@Nullable TargetPair target); /** @@ -59,12 +46,10 @@ public interface MethodContext { @Nullable Pair> findInjectionTargetCandidates(ClassLookup lookup, boolean ignoreDesc); - void updateDescription(MethodTransform transform, List parameters); + void updateDescription(List parameters); boolean isStatic(); - boolean isCancellable(); - @Nullable List getTargetMethodLocals(TargetPair target); @@ -78,19 +63,9 @@ default List getTargetMethodLocals(TargetPair target, int startPo List getLvtCompatLevelsOrdered(); - boolean capturesLocals(); - boolean failsDirtyInjectionCheck(); - boolean hasInjectionPointValue(String value); - boolean isNotRequired(); boolean hasValidSlice(TargetPair target); - - void recordAudit(Object transform, String message, Object... args); - - record LocalVariable(int index, Type type) {} - - record TargetPair(ClassNode classNode, MethodNode methodNode) {} } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransform.java b/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransform.java deleted file mode 100644 index 463680c2..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransform.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.sinytra.adapter.patch.api; - -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; - -import java.util.Collection; -import java.util.Set; - -public interface MethodTransform { - default Collection getAcceptedAnnotations() { - return Set.of(); - } - - default Patch.Result apply(MethodContext methodContext) { - return apply(methodContext.getMixinClass(), methodContext.getMixinMethod(), methodContext, methodContext.patchContext()); - } - - Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context); -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java b/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java deleted file mode 100644 index 60799515..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodTransformBuilder.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.sinytra.adapter.patch.api; - -import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMethodAccess; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMixinType; - -import java.util.List; -import java.util.function.Consumer; - -public interface MethodTransformBuilder> { - T transformParams(Consumer consumer); - - T modifyTarget(String... methods); - - T modifyMethodAccess(ModifyMethodAccess.AccessChange... changes); - - T extractMixin(String targetClass); - - T improveModifyVar(); - - T modifyMixinType(String newType, Consumer consumer); - - T transform(MethodTransform transformer); - - T transformMethods(List transformers); - - T chain(Consumer consumer); - - interface Class> extends MethodTransformBuilder { - default T modifyInjectionPoint(String value, String target) { - return modifyInjectionPoint(value, target, false); - } - - T modifyInjectionPoint(String value, String target, boolean resetValues); - - default T modifyInjectionPoint(String target) { - return modifyInjectionPoint(null, target); - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/Patch.java b/definition/src/main/java/org/sinytra/adapter/patch/api/Patch.java deleted file mode 100644 index b61203a7..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/Patch.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.sinytra.adapter.patch.api; - -import org.objectweb.asm.Type; -import org.objectweb.asm.commons.InstructionAdapter; -import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.ClassPatchInstance; -import org.sinytra.adapter.patch.InterfacePatchInstance; -import org.sinytra.adapter.patch.PatchInstance; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public interface Patch { - static ClassPatchBuilder builder() { - return new ClassPatchInstance.ClassPatchBuilderImpl(); - } - - static InterfacePatchBuilder interfaceBuilder() { - return new InterfacePatchInstance.InterfaceClassPatchBuilderImpl(); - } - - Result apply(ClassNode classNode, PatchEnvironment environment); - - enum Result { - PASS, - APPLY, - COMPUTE_FRAMES; - - public Result or(Result other) { - if (this == PASS && other != PASS) { - return other; - } - if (this == APPLY && other == COMPUTE_FRAMES) { - return COMPUTE_FRAMES; - } - return this; - } - } - - interface Builder> extends MethodTransformBuilder { - T targetClass(String... targets); - - T targetMixinType(String... annotationDescs); - - T targetAnnotationValues(Predicate values); - - T modifyTargetClasses(Consumer> consumer); - - T transform(List classTransforms); - - T transform(ClassTransform transformer); - - PatchInstance build(); - } - - interface ClassPatchBuilder extends Builder, MethodTransformBuilder.Class { - ClassPatchBuilder targetMethod(String... targets); - - default ClassPatchBuilder targetInjectionPoint(String target) { - return targetInjectionPoint(null, target); - } - - ClassPatchBuilder targetInjectionPoint(String value, String target); - - default ClassPatchBuilder targetConstant(double doubleValue) { - return targetAnnotationValues(handle -> handle.getNested("constant") - .flatMap(cst -> cst.getValue("doubleValue") - .map(val -> val.get() == doubleValue)) - .orElseGet(() -> handle.getNested("at") - .flatMap(at -> at.getValue("value").map(s -> s.get().equals("CONSTANT") && - at.>getValue("args").map(AnnotationValueHandle::get).map(t -> t.size() == 1 - && (t.getFirst().equals("doubleValue=" + doubleValue + "D") || t.getFirst().equals("doubleValue=" + doubleValue))) - .orElse(false))) - .orElse(false))); - } - - ClassPatchBuilder divertRedirector(Consumer patcher); - - ClassPatchBuilder disable(); - } - - interface InterfacePatchBuilder extends Builder { - InterfacePatchBuilder targetField(String... targets); - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchResult.java b/definition/src/main/java/org/sinytra/adapter/patch/api/PatchResult.java new file mode 100644 index 00000000..b98e90e2 --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/api/PatchResult.java @@ -0,0 +1,17 @@ +package org.sinytra.adapter.patch.api; + +public enum PatchResult { + PASS, + APPLY, + COMPUTE_FRAMES; + + public PatchResult or(PatchResult other) { + if (this == PASS && other != PASS) { + return other; + } + if (this == APPLY && other == COMPUTE_FRAMES) { + return COMPUTE_FRAMES; + } + return this; + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/TargetPair.java b/definition/src/main/java/org/sinytra/adapter/patch/api/TargetPair.java new file mode 100644 index 00000000..80e4672a --- /dev/null +++ b/definition/src/main/java/org/sinytra/adapter/patch/api/TargetPair.java @@ -0,0 +1,7 @@ +package org.sinytra.adapter.patch.api; + +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +public record TargetPair(ClassNode classNode, MethodNode methodNode) { +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java index 2050d565..8f26b015 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java @@ -2,15 +2,14 @@ import com.mojang.datafixers.util.Pair; 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.*; +import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.api.ClassTransform; -import org.sinytra.adapter.patch.api.Patch; +import org.sinytra.adapter.next.transform.ClassTransformer; import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.patch.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; @@ -18,13 +17,13 @@ import java.util.List; import java.util.Map; -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; -public class FieldTypeUsageTransformer implements ClassTransform { +public class FieldTypeUsageTransformer implements ClassTransformer { private static final Logger LOGGER = LogUtils.getLogger(); @Override - public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle annotation, PatchContext context) { + public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context) { BytecodeFixerUpper bfu = context.environment().bytecodeFixerUpper(); boolean applied = false; if (bfu != null) { @@ -85,7 +84,7 @@ public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle updatedTypes, MethodNode method, FieldInsnNode finsn) { diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyVarUpgradeToModifyExprVal.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyVarUpgradeToModifyExprVal.java deleted file mode 100644 index 85c57e65..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyVarUpgradeToModifyExprVal.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.sinytra.adapter.patch.transformer; - -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.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMixinType; - -import java.util.Collection; -import java.util.Set; - -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_SHIFT; - -/** - * Original mixin: - * - *
{@code @ModifyVariable(
- *     method = "exampleMethod",
- *     at = @At(
- *         value = "INVOKE",
- *         target = "someOtherMethod()I",
- *         shift = At.Shift.BY,
- *         by = 2
- *     )
- * )
- * private void someMethodMixin(int original) {
- *     return original * 2;
- * }
- * }
- *

- * Original target: - * - *

{@code
- * public int exampleMethod() {
- *     int i = someOtherMethod();
- * >>> i = localvar$zfk000$someMethodMixin(i);
- *     // ...
- * }
- * }
- *

- * Patched target: - *

{@code
- * public int exampleMethod() {
- * <<< int i = someOtherMethod();
- * >>> int i = modifyExpressionValue$zfk000$someMethodMixin(someOtherMethod());
- *     // ...
- * }
- * }
- *

- * Patched mixin: - * - *

{@code @ModifyExpressionValue(
- *     method = "exampleMethod",
- *     at = @At(
- *         value = "INVOKE",
- *         target="someOtherMethod()I"
- *     )
- * )
- * private void someMethodMixin(int original) {
- *     return original * 2;
- * }
- * }
- */ -public class ModifyVarUpgradeToModifyExprVal implements MethodTransform { - public static final ModifyVarUpgradeToModifyExprVal INSTANCE = new ModifyVarUpgradeToModifyExprVal(); - private static final Collection ALLOWED_VALUES = Set.of("INVOKE", "INVOKE_ASSIGN"); - - @Override - public Collection getAcceptedAnnotations() { - return Set.of(MixinConstants.MODIFY_VAR); - } - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationHandle injectionAnnotation = methodContext.injectionPointAnnotation(); - // Conditions must be met: - // - The injection target value is INVOKE - // - The target is shifted BY 2 - if (injectionAnnotation == null || injectionAnnotation.getValue("value").filter(v -> ALLOWED_VALUES.contains(v.get())).isEmpty() || injectionAnnotation.getValue(AT_SHIFT).isEmpty() || injectionAnnotation.getValue("by").isEmpty()) { - return Patch.Result.PASS; - } - AnnotationValueHandle target = injectionAnnotation.getValue("target").orElse(null); - if (target == null) { - return null; - } - // Modify mixin type - MethodTransform transform = new ModifyMixinType(MixinConstants.MODIFY_EXPR_VAL, b -> b - .sameTarget() - .injectionPoint("INVOKE", target.get())); - return transform.apply(classNode, methodNode, methodContext, context); - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java deleted file mode 100644 index 4f2ece2a..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInheritedInjectionPointPatch.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynamic; - -import org.objectweb.asm.Opcodes; -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.*; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.List; - -public class DynamicInheritedInjectionPointPatch implements MethodTransform { - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationHandle atNode = methodContext.injectionPointAnnotation(); - if (atNode == null) { - return Patch.Result.PASS; - } - if (atNode.getValue("value").map(v -> !v.get().equals("INVOKE")).orElse(true)) { - return Patch.Result.PASS; - } - AnnotationValueHandle target = atNode.getValue("target").orElse(null); - if (target == null) { - return Patch.Result.PASS; - } - MethodQualifier q = methodContext.getInjectionPointMethodQualifier(); - if (q == null) { - return Patch.Result.PASS; - } - MethodContext.TargetPair targetPair = methodContext.findDirtyInjectionTarget(); - if (targetPair == null) { - return Patch.Result.PASS; - } - List insns = methodContext.findInjectionTargetInsns(targetPair); - if (!insns.isEmpty()) { - return Patch.Result.PASS; - } - String owner = q.internalOwnerName(); - for (AbstractInsnNode insn : targetPair.methodNode().instructions) { - if (insn instanceof MethodInsnNode minsn && minsn.name.equals(q.name()) && minsn.desc.equals(q.desc()) && !minsn.owner.equals(owner) - && (context.environment().inheritanceHandler().isClassInherited(minsn.owner, owner) || isFixedField(minsn, context)) - ) { - target.set(MethodQualifier.create(minsn).asDescriptor()); - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.REDIRECT) && minsn.getOpcode() != Opcodes.INVOKESTATIC) { - methodNode.visitParameterAnnotation(0, MixinConstants.COERCE, false); - } - return Patch.Result.APPLY; - } - } - return Patch.Result.PASS; - } - - private boolean isFixedField(AbstractInsnNode insn, PatchContext context) { - for (AbstractInsnNode prev = insn.getPrevious(); prev != null; prev = prev.getPrevious()) { - if (prev instanceof LabelNode) { - break; - } - if (prev instanceof FieldInsnNode finsn) { - BytecodeFixerUpper bfu = context.environment().bytecodeFixerUpper(); - return bfu.getFieldTypeChange(finsn.owner, finsn.name) != null; - } - } - return false; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java deleted file mode 100644 index 346769a0..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicModifyVarAtReturnPatch.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynamic; - -import com.mojang.datafixers.util.Pair; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -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.transformer.operation.unit.ModifyMixinType; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.MockMixinRuntime; -import org.spongepowered.asm.mixin.injection.modify.LocalVariableDiscriminator; -import org.spongepowered.asm.mixin.injection.struct.InjectionInfo; -import org.spongepowered.asm.mixin.injection.struct.Target; - -import java.util.Collection; -import java.util.List; -import java.util.Set; - -/** - * Original mixin: - * - *
{@code @ModifyVariable(
- *     method = "exampleMethod",
- *     at = @At("RETURN")
- * )
- * private void someMethodMixin(int original) {
- *     return original * 2;
- * }
- * }
- *

- * Original target: - * - *

{@code
- * public int exampleMethod() {
- *     int i = 10;
- *     // ...
- * <<< return i;
- * >>> return localvar$zfk000$someMethodMixin(i);
- * }
- * }
- *

- * Patched target: - *

{@code
- * public int exampleMethod() {
- *     int i = 10;
- *     // ...
- * <<< return EventHooks.wrapVariable(i);
- * >>> return EventHooks.wrapVariable(modify$zfk000$someMethodMixin(i));
- * }
- * }
- *

- * Patched mixin: - * - *

{@code @ModifyArg(
- *     method = "exampleMethod",
- *     at = @At(
- *         value = "INVOKE",
- *         target="Lcom/example/EventHooks;wrapVariable(I)I"
- *     ),
- *     index = 0
- * )
- * private void someMethodMixin(int original) {
- *     return original * 2;
- * }
- * }
- */ -public class DynamicModifyVarAtReturnPatch implements MethodTransform { - @Override - public Collection getAcceptedAnnotations() { - return Set.of(MixinConstants.MODIFY_VAR); - } - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationHandle injectionPointAnnotation = methodContext.injectionPointAnnotation(); - if (injectionPointAnnotation == null) { - return Patch.Result.PASS; - } - AnnotationValueHandle targetHandle = injectionPointAnnotation.getValue("value").orElse(null); - if (targetHandle == null || !targetHandle.get().equals("RETURN")) { - return Patch.Result.PASS; - } - int ordinal = injectionPointAnnotation.getValue("ordinal").map(AnnotationValueHandle::get).orElse(-1); - // Find injection targets - MethodContext.TargetPair cleanTarget = methodContext.findCleanInjectionTarget(); - if (cleanTarget == null) { - return Patch.Result.PASS; - } - MethodContext.TargetPair dirtyTarget = methodContext.findDirtyInjectionTarget(); - if (dirtyTarget == null) { - return Patch.Result.PASS; - } - Pair cleanTargetPair = getTargetPair(classNode, methodNode, methodContext, context, cleanTarget, ordinal); - // In CLEAN, previous insn is VarInsn for the modified variable - if (cleanTargetPair == null || !(cleanTargetPair.getFirst() instanceof VarInsnNode cleanVarInsn) || cleanVarInsn.var != cleanTargetPair.getSecond()) { - return Patch.Result.PASS; - } - // In DIRTY, previous insn (as in, before the RETURN insn) is a method call - Pair dirtyTargetPair = getTargetPair(classNode, methodNode, methodContext, context, dirtyTarget, ordinal); - // In CLEAN, previous insn is VarInsn for the modified variable - if (dirtyTargetPair == null || !(dirtyTargetPair.getFirst() instanceof MethodInsnNode dirtyMinsn)) { - return Patch.Result.PASS; - } - // Get method call argument instructions - List args = MethodCallAnalyzer.getMethodCallSrcInsns(dirtyTarget.methodNode(), dirtyMinsn); - if (args == null) { - return Patch.Result.PASS; - } - - Patch.Result result = Patch.Result.PASS; - for (int i = 0; i < args.size(); i++) { - AbstractInsnNode insn = args.get(i); - if (insn instanceof VarInsnNode varInsn && varInsn.var == cleanTargetPair.getSecond()) { - if (result != Patch.Result.PASS) { - // Cannot apply twice - return Patch.Result.PASS; - } - String qualifier = MethodQualifier.create(dirtyMinsn).asDescriptor(); - final int index = i; - methodContext.recordAudit(this, "Redirect RETURN variable modifier to parameter %s of method call to %s", i, qualifier); - MethodTransform transform = new ModifyMixinType(MixinConstants.MODIFY_ARG, b -> b.sameTarget() - .injectionPoint("INVOKE", qualifier) - .putValue("index", index)); - result = transform.apply(classNode, methodNode, methodContext, context); - } - } - - return result; - } - - private static Pair getTargetPair(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, MethodContext.TargetPair injectionTarget, int ordinal) { - // Find injection point insn - List targetInsns = methodContext.findInjectionTargetInsns(injectionTarget); - if (targetInsns.isEmpty()) { - return null; - } - int index = ordinal == -1 ? targetInsns.size() - 1 : ordinal; - if (index >= targetInsns.size()) { - return null; - } - AbstractInsnNode targetInsn = targetInsns.get(index); - // Find modified variable - LocalVariableDiscriminator discriminator = LocalVariableDiscriminator.parse(methodContext.methodAnnotation().unwrap()); - InjectionInfo injectionInfo = MockMixinRuntime.forInjectionInfo(classNode.name, injectionTarget.classNode().name, context.environment()); - Type returnType = Type.getReturnType(methodNode.desc); - Target target = MockMixinRuntime.createMixinTarget(injectionTarget); - LocalVariableDiscriminator.Context ctx = new LocalVariableDiscriminator.Context(injectionInfo, returnType, discriminator.isArgsOnly(), target, targetInsn); - int local = discriminator.findLocal(ctx); - return Pair.of(targetInsn, local); - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/LocalCaptureUpgradePreprocessor.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/LocalCaptureUpgradePreprocessor.java deleted file mode 100644 index 30b9d743..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/LocalCaptureUpgradePreprocessor.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.sinytra.adapter.patch.transformer.dynamic; - -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.*; -import org.sinytra.adapter.patch.util.AdapterUtil; - -import java.util.ArrayList; -import java.util.List; - -public class LocalCaptureUpgradePreprocessor implements MethodTransform { - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - if (methodContext.findCleanInjectionTarget() == null) { - return Patch.Result.PASS; - } - - Data data = prepare(methodContext); - if (data != null) { - PatchAuditTrail auditTrail = context.environment().auditTrail(); - Patch.Result result = apply(methodNode, methodContext, auditTrail, data); - auditTrail.recordResult(methodContext, PatchAuditTrail.Match.FULL); - return result; - } - - return Patch.Result.PASS; - } - - public record Data(AdapterUtil.CapturedLocals capturedLocals, LocalVarAnalyzer.CapturedLocalsTransform transform) { - } - - @Nullable - public LocalCaptureUpgradePreprocessor.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); - } - - @Nullable - public Patch.Result apply(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 result; - } -} 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 6ef83be5..08d069b6 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 @@ -6,11 +6,7 @@ import org.objectweb.asm.tree.*; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -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.PatchContext; -import org.sinytra.adapter.patch.transformer.ModifyArgsOffsetUpgrader; +import org.sinytra.adapter.patch.api.*; import java.util.ArrayList; import java.util.Arrays; @@ -20,11 +16,11 @@ public record InjectParameterTransform(int index, Type type) implements ParameterTransformer { @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { boolean isNonStatic = (methodNode.access & Opcodes.ACC_STATIC) == 0; final int index = this.index + offset; if (index >= parameters.size() + 1) { - return Patch.Result.PASS; + return PatchResult.PASS; } AnnotationHandle annotation = methodContext.methodAnnotation(); @@ -36,12 +32,12 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont indexHandle.set(indexValue + 1); } }); - return Patch.Result.APPLY; + return PatchResult.APPLY; } if (annotation.matchesDesc(MixinConstants.MODIFY_ARGS)) { ModifyArgsOffsetUpgrader.upgradeAfterParamInsert(methodNode, this.index); - return Patch.Result.APPLY; + return PatchResult.APPLY; } LocalVariableNode self = methodNode.localVariables.stream().filter(lvn -> lvn.index == 0).findFirst().orElseThrow(); @@ -58,7 +54,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont methodNode.localVariables.add(index + (isNonStatic ? 1 : 0), new LocalVariableNode(newParameter.name, type.getDescriptor(), null, self.start, self.end, lvtIndex)); }); - return Patch.Result.APPLY; + return PatchResult.APPLY; } public static void offsetParameters(MethodNode methodNode, int paramIndex) { 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 845c3f38..1849acf5 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 @@ -4,10 +4,10 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; 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.locals.LVTSnapshot; +import org.sinytra.adapter.patch.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; @@ -15,13 +15,13 @@ import java.util.List; import java.util.function.Consumer; -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; public record InlineParameterTransformer(int target, Consumer adapter) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { final int index = this.target + offset; LOGGER.info(MIXINPATCH, "Inlining parameter {} of method {}.{}", index, classNode.name, methodNode.name); final int replaceIndex = -999 + index; @@ -46,6 +46,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont } } - return Patch.Result.COMPUTE_FRAMES; + return PatchResult.COMPUTE_FRAMES; } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetUpgrader.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ModifyArgsOffsetUpgrader.java similarity index 96% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetUpgrader.java rename to definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ModifyArgsOffsetUpgrader.java index 9fa78359..0c0ed17e 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/ModifyArgsOffsetUpgrader.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ModifyArgsOffsetUpgrader.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer; +package org.sinytra.adapter.patch.transformer.operation.param; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; 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 14c4931e..0ae78684 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 @@ -9,20 +9,20 @@ import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; 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.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; import java.util.List; -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; public record MoveParametersTransformer(int from, int to) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { final int paramIndex = this.from + offset; LOGGER.info(MIXINPATCH, "Moving parameter from index {} to {} in method {}.{}", this.from, this.to, classNode.name, methodNode.name); @@ -49,6 +49,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont parameters.add(this.to > paramIndex ? this.to - 1 : this.to, type); - return Patch.Result.COMPUTE_FRAMES; + return PatchResult.COMPUTE_FRAMES; } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformTarget.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformTarget.java deleted file mode 100644 index 8aada7f7..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformTarget.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.param; - -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.MixinConstants; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; - -@Deprecated // TODO Should no longer be needed in UTP -public enum ParamTransformTarget { - ALL, - METHOD(MixinConstants.INJECT, MixinConstants.OVERWRITE, MixinConstants.MODIFY_VAR), - INJECTION_POINT(MixinConstants.REDIRECT, MixinConstants.MODIFY_ARG, MixinConstants.MODIFY_ARGS, MixinConstants.WRAP_OPERATION), - METHOD_EXT(MixinConstants.INJECT, MixinConstants.REDIRECT, MixinConstants.OVERWRITE, MixinConstants.MODIFY_VAR); - - private final Set targetMixinTypes; - - ParamTransformTarget(String... targetMixinTypes) { - this.targetMixinTypes = new HashSet<>(Arrays.asList(targetMixinTypes)); - } - - public static ParamTransformTarget from(String name) { - return valueOf(name.toUpperCase(Locale.ROOT)); - } - - public Set getTargetMixinTypes() { - return this.targetMixinTypes; - } - - public boolean test(AnnotationHandle methodAnnotation) { - return this.targetMixinTypes.contains(methodAnnotation.getDesc()); - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java index 4c610dbd..e1eaa9ce 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java @@ -4,11 +4,11 @@ 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.Patch; import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.PatchResult; import java.util.List; public interface ParameterTransformer { - Patch.Result apply(final ClassNode classNode, final MethodNode methodNode, final MethodContext methodContext, final PatchContext context, final List parameters, final int offset); + PatchResult apply(final ClassNode classNode, final MethodNode methodNode, final MethodContext methodContext, final PatchContext context, final List parameters, final int offset); } 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 48477bc5..6f9d8f83 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 @@ -6,8 +6,8 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; 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.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.List; @@ -18,7 +18,7 @@ public RemoveParameterTransformer(int index) { } @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { final int target = this.index() + offset; final int lvtIndex = ParamTransformationUtil.calculateLVTIndex(parameters, !methodContext.isStatic(), target); @@ -40,6 +40,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont methodNode.invisibleParameterAnnotations = AdapterUtil.removeArrayElement(methodNode.invisibleParameterAnnotations, this.index, List[]::new); parameters.remove(target); - return Patch.Result.COMPUTE_FRAMES; + return PatchResult.COMPUTE_FRAMES; } } 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 881cf5d2..5a486072 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 @@ -5,19 +5,16 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -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.PatchContext; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.patch.api.*; import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; import org.sinytra.adapter.patch.fixes.TypeAdapter; import org.slf4j.Logger; import java.util.List; -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; import static org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil.findWrapOperationOriginalCall; // TODO Just add @Coerce if the types are inherited @@ -29,11 +26,11 @@ public ReplaceParametersTransformer(int index, Type type) { } @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { final int paramIndex = this.index + offset; if (methodNode.parameters.size() <= paramIndex) { - return Patch.Result.PASS; + return PatchResult.PASS; } LOGGER.info(MIXINPATCH, "Replacing parameter {} with type {} in {}.{}", paramIndex, this.type, classNode.name, methodNode.name); @@ -87,6 +84,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont } } - return Patch.Result.COMPUTE_FRAMES; + return PatchResult.COMPUTE_FRAMES; } } 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 580d885d..0d852adc 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 @@ -6,8 +6,8 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; 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.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; @@ -19,14 +19,14 @@ public record SubstituteParameterTransformer(int target, int substitute) impleme private static final Logger LOGGER = LogUtils.getLogger(); @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { final int paramIndex = this.target + offset; final int substituteParamIndex = this.substitute + offset; final boolean isNonStatic = !methodContext.isStatic(); final int localIndex = calculateLVTIndex(parameters, isNonStatic, paramIndex); if (methodNode.parameters.size() <= paramIndex) { - return Patch.Result.PASS; + return PatchResult.PASS; } LVTSnapshot.with(methodNode, () -> { @@ -39,6 +39,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont AdapterUtil.replaceLVT(methodNode, idx -> idx == localIndex ? substituteIndex : idx); }); - return Patch.Result.COMPUTE_FRAMES; + return PatchResult.COMPUTE_FRAMES; } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SwapParametersTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SwapParametersTransformer.java index 1e891ba9..c946bd7e 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SwapParametersTransformer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SwapParametersTransformer.java @@ -4,8 +4,8 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; 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.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.SingleValueHandle; import org.slf4j.Logger; @@ -13,13 +13,13 @@ import java.util.List; import java.util.function.Consumer; -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; public record SwapParametersTransformer(int from, int to) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { int from = offset + this.from; int to = offset + this.to; boolean nonStatic = !methodContext.isStatic(); @@ -48,7 +48,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont .andThen(swapLVT(methodNode, toOldLVT, fromNewLVT)) .accept(null); - return Patch.Result.COMPUTE_FRAMES; + return PatchResult.COMPUTE_FRAMES; } public static Consumer swapLVT(MethodNode methodNode, int from, int to) { diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/TransformParameters.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/TransformParameters.java index 0a4ef32d..22f68fa3 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/TransformParameters.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/TransformParameters.java @@ -3,37 +3,40 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import com.mojang.datafixers.util.Pair; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.*; - -import java.util.*; +import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.PatchResult; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.function.Consumer; -public record TransformParameters(List transformers, boolean withOffset, ParamTransformTarget targetType) implements MethodTransform { - - @Override - public Collection getAcceptedAnnotations() { - return this.targetType.getTargetMixinTypes(); - } +public record TransformParameters(List transformers, boolean withOffset) { - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { + // TODO + public PatchResult apply(MethodContext methodContext) { + ClassNode classNode = methodContext.getMixinClass(); + MethodNode methodNode = methodContext.getMixinMethod(); + PatchContext context = methodContext.patchContext(); + Type[] params = Type.getArgumentTypes(methodNode.desc); List newParameterTypes = new ArrayList<>(Arrays.asList(params)); - Patch.Result result = Patch.Result.PASS; + PatchResult result = PatchResult.PASS; int offset = calculateOffset(methodContext); for (ParameterTransformer transform : transformers) { result = result.or(transform.apply(classNode, methodNode, methodContext, context, newParameterTypes, offset)); } - if (result != Patch.Result.PASS) { - methodContext.updateDescription(this, newParameterTypes); + if (result != PatchResult.PASS) { + methodContext.updateDescription(newParameterTypes); } return result; @@ -41,14 +44,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont private int calculateOffset(MethodContext methodContext) { AnnotationHandle annotation = methodContext.methodAnnotation(); - if (this.targetType == ParamTransformTarget.METHOD_EXT && annotation.matchesDesc(MixinConstants.REDIRECT)) { - MethodNode targetMethod = Optional.ofNullable(methodContext.getInjectionPointMethodQualifier()) - .flatMap(q -> methodContext.patchContext().environment().dirtyClassLookup().findMethod(q.internalOwnerName(), q.name(), q.desc())) - .orElse(null); - if (targetMethod != null) { - return ((targetMethod.access & Opcodes.ACC_STATIC) == 0 ? 1 : 0) + Type.getArgumentTypes(targetMethod.desc).length; - } - } // If it's a redirect, the first local variable (index 1) is the object instance boolean needsLocalOffset = annotation.matchesDesc(MixinConstants.REDIRECT) || annotation.matchesDesc(MixinConstants.WRAP_OPERATION); return !methodContext.isStatic() && this.withOffset && needsLocalOffset ? 1 : 0; @@ -62,7 +57,6 @@ public static Builder builder() { public static class Builder { private final List transformers = new ArrayList<>(); private boolean offset = false; - private ParamTransformTarget targetType = ParamTransformTarget.ALL; public Builder transform(ParameterTransformer transformer) { this.transformers.add(transformer); @@ -128,11 +122,6 @@ public Builder withOffset(boolean offset) { return this; } - public Builder targetType(ParamTransformTarget targetType) { - this.targetType = targetType; - return this; - } - public Builder chain(Consumer consumer) { consumer.accept(this); return this; @@ -140,7 +129,7 @@ public Builder chain(Consumer consumer) { @CheckReturnValue public TransformParameters build() { - return new TransformParameters(this.transformers, this.offset, this.targetType); + return new TransformParameters(this.transformers, this.offset); } } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DisableMixin.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DisableMixin.java deleted file mode 100644 index 406051d2..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DisableMixin.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; - -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; - -public class DisableMixin implements MethodTransform { - public static final DisableMixin INSTANCE = new DisableMixin(); - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - methodContext.recordAudit(this, "Remove mixin method"); - context.postApply(() -> classNode.methods.remove(methodNode)); - return Patch.Result.APPLY; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DivertRedirectorTransform.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DivertRedirectorTransform.java deleted file mode 100644 index db820ef3..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/DivertRedirectorTransform.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; - -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.commons.InstructionAdapter; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; -import org.sinytra.adapter.patch.api.*; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.Collection; -import java.util.Set; -import java.util.function.Consumer; - -public record DivertRedirectorTransform(Consumer patcher) implements MethodTransform { - - @Override - public Collection getAcceptedAnnotations() { - return Set.of(MixinConstants.REDIRECT); - } - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - String value = methodContext.injectionPointAnnotation().getValue("value").map(AnnotationValueHandle::get).orElse(null); - if (MixinAnnotationConstants.AT_VAL_INVOKE.equals(value)) { - MethodQualifier target = methodContext.getInjectionPointMethodQualifier(); - if (target != null) { - boolean applied = false; - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof MethodInsnNode minsn && target.matches(minsn)) { - for (AbstractInsnNode previous = insn.getPrevious(); previous != null; previous = previous.getPrevious()) { - if (previous instanceof LabelNode) { - MethodNode dummy = new MethodNode(); - InstructionAdapter adapter = new InstructionAdapter(dummy); - - LabelNode gotoTarget = new LabelNode(); - dummy.instructions.add(gotoTarget); - this.patcher.accept(adapter); - methodNode.instructions.insert(minsn, dummy.instructions); - methodNode.instructions.insert(previous, new JumpInsnNode(Opcodes.GOTO, gotoTarget)); - applied = true; - break; - } - } - } - } - if (applied) { - return Patch.Result.APPLY; - } - } - } - return Patch.Result.PASS; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java deleted file mode 100644 index 115c266c..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionPoint.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; - -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -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.MethodTransform; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.api.PatchContext; - -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_SHIFT; - -public record ModifyInjectionPoint(@Nullable String value, String target, boolean resetValues) implements MethodTransform { - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationHandle annotation = methodContext.injectionPointAnnotation(); - if (annotation == null) { - // Likely an @Overwrite - return Patch.Result.PASS; - } - if (this.value != null) { - AnnotationValueHandle handle = annotation.getValue("value") - .orElseThrow(() -> new IllegalArgumentException("Missing value handle")); - handle.set(this.value); - } - methodContext.recordAudit(this, "Change injection point to %s", this.target); - annotation.setOrAppendNonNull("target", this.target); - if (this.resetValues) { - methodContext.methodAnnotation().removeValues("slice"); - annotation.removeValues("ordinal", AT_SHIFT, "by", "opcode"); - } - return Patch.Result.APPLY; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java deleted file mode 100644 index bfc11d15..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyInjectionTarget.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; - -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.*; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.List; - -public record ModifyInjectionTarget(List replacementMethods) implements MethodTransform { - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationHandle annotation = methodContext.methodAnnotation(); - - methodContext.recordAudit(this, "Change mixin target to %s", this.replacementMethods); - if (annotation.matchesDesc(MixinConstants.OVERWRITE)) { - if (this.replacementMethods.size() > 1) { - throw new IllegalStateException("Cannot determine replacement @Overwrite method name, multiple specified: " + this.replacementMethods); - } - String replacement = this.replacementMethods.getFirst(); - MethodQualifier.create(replacement) - .map(MethodQualifier::name) - .ifPresent(str -> methodNode.name = str); - } else { - annotation.>getValue("method").ifPresentOrElse( - handle -> handle.set(this.replacementMethods), - () -> annotation.appendValue("method", this.replacementMethods) - ); - } - - return Patch.Result.APPLY; - } -} \ No newline at end of file diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMethodAccess.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMethodAccess.java deleted file mode 100644 index 0b9abeca..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMethodAccess.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; - -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.api.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public record ModifyMethodAccess(List changes) implements MethodTransform { - public record AccessChange(boolean add, int modifier) {} - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - Patch.Result result = Patch.Result.PASS; - for (AccessChange change : this.changes) { - if (change.add) { - if ((methodNode.access & change.modifier) == 0) { - methodContext.recordAudit(this, "Adding access modifier %s", change.modifier); - methodNode.access |= change.modifier; - result = Patch.Result.APPLY; - if (change.modifier == Opcodes.ACC_STATIC && methodContext.methodAnnotation().matchesDesc(MixinConstants.INJECT)) { - List types = methodContext.targetTypes(); - if (types.size() == 1) { - Type[] params = Type.getArgumentTypes(methodNode.desc); - List newParams = new ArrayList<>(Arrays.asList(params)); - newParams.addFirst(types.getFirst()); - - methodContext.updateDescription(this, newParams); - } else { - throw new IllegalStateException("Cannot automatically determine target instance type for mixin " + classNode.name); - } - } - } - } else { - if ((methodNode.access & change.modifier) != 0) { - methodContext.recordAudit(this, "Removing access modifier %s", change.modifier); - methodNode.access &= ~change.modifier; - if (change.modifier == Opcodes.ACC_STATIC) { - LocalVariableNode firstParam = methodNode.localVariables.stream().filter(lvn -> lvn.index == 0).findFirst().orElseThrow(); - // Offset everything by 1 - for (LocalVariableNode lvn : methodNode.localVariables) { - lvn.index++; - } - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof VarInsnNode varInsn) { - varInsn.var++; - } - } - // Insert instance local variable - methodNode.localVariables.add(new LocalVariableNode("this", Type.getObjectType(classNode.name).getDescriptor(), null, firstParam.start, firstParam.end, 0)); - result = Patch.Result.COMPUTE_FRAMES; - } else { - result = Patch.Result.APPLY; - } - } - } - } - return result; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMixinType.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMixinType.java deleted file mode 100644 index fdd5c9f1..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyMixinType.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.tree.AnnotationNode; -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.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; - -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - -public record ModifyMixinType(String replacementDesc, Consumer consumer) implements MethodTransform { - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationHandle annotation = methodContext.methodAnnotation(); - AnnotationNode replacement = new AnnotationNode(this.replacementDesc); - Builder builder = new Builder(annotation.getAllValues(), replacement); - this.consumer.accept(builder); - for (int i = 0; i < methodNode.visibleAnnotations.size(); i++) { - AnnotationNode methodAnn = methodNode.visibleAnnotations.get(i); - if (methodAnn == annotation.unwrap()) { - methodNode.visibleAnnotations.set(i, replacement); - annotation.refresh(replacement); - methodContext.recordAudit(this, "Modify type to %s", this.replacementDesc); - break; - } - } - return Patch.Result.APPLY; - } - - public static class Builder { - private final Map> annotationValues; - private final AnnotationNode replacement; - - public Builder(Map> annotationValues, AnnotationNode replacement) { - this.annotationValues = annotationValues; - this.replacement = replacement; - } - - public Builder sameTarget() { - AnnotationValueHandle> method = (AnnotationValueHandle>) this.annotationValues.get("method"); - if (method != null) { - putValue("method", method.get()); - } - return this; - } - - public Builder putValue(String key, Object value) { - this.replacement.visit(key, value); - return this; - } - - public Builder injectionPoint(String value) { - return injectionPoint(value, ""); - } - - public Builder injectionPoint(String value, String target) { - return injectionPoint(value, target, b -> {}); - } - - public Builder injectionPoint(String value, String target, Consumer builder) { - AnnotationVisitor atNode = this.replacement.visitAnnotation("at", MixinConstants.AT); - atNode.visit("value", value); - if (!target.isEmpty()) { - atNode.visit("target", target); - } - builder.accept(atNode); - return this; - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyTargetClasses.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyTargetClasses.java deleted file mode 100644 index 4c1ae99c..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ModifyTargetClasses.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; - -import org.objectweb.asm.Type; -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 org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -public record ModifyTargetClasses(Consumer> consumer) implements MethodTransform { - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationValueHandle handle = methodContext.classAnnotation(); - if (handle != null && handle.getKey().equals("value")) { - AnnotationValueHandle> valueHandle = (AnnotationValueHandle>) handle; - - List types = new ArrayList<>(valueHandle.get()); - this.consumer.accept(types); - valueHandle.set(types); - methodContext.recordAudit(this, "Modify target classes to %s", types); - return Patch.Result.APPLY; - } - return Patch.Result.PASS; - } -} 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 aba09ca4..5c3b305a 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 @@ -17,7 +17,10 @@ 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.api.TargetPair; import org.slf4j.Logger; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; import org.spongepowered.asm.mixin.gen.AccessorInfo; import java.io.PrintWriter; @@ -30,6 +33,7 @@ public final class AdapterUtil { public static final String LAMBDA_PREFIX = "lambda$"; + public static final Marker MIXINPATCH = MarkerFactory.getMarker("MIXINPATCH"); private static final Pattern FIELD_REF_PATTERN = Pattern.compile("^(?L.+?;)?(?[^:]+)?:(?.+)?$"); private static final Logger LOGGER = LogUtils.getLogger(); @@ -200,7 +204,7 @@ public static CapturedLocals getCapturedLocals(MethodNode methodNode, MethodCont LOGGER.debug("Missing CI or CIR argument in injector of type {}", annotation.getDesc()); return null; } - MethodContext.TargetPair target = methodContext.findDirtyInjectionTarget(); + TargetPair target = methodContext.findDirtyInjectionTarget(); if (target == null) { return null; } @@ -244,7 +248,7 @@ public static T[] removeArrayElement(T[] arr, int index, IntFunction ar return list.toArray(arrayGen); } - public record CapturedLocals(MethodContext.TargetPair target, boolean isStatic, int paramLocalStart, int paramLocalEnd, int lvtOffset, + public record CapturedLocals(TargetPair target, boolean isStatic, int paramLocalStart, int paramLocalEnd, int lvtOffset, List expected, LocalVariableLookup lvt) { } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java b/definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java deleted file mode 100644 index 2fc91cc1..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodTransformBuilderImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.sinytra.adapter.patch.util; - -import org.sinytra.adapter.patch.api.MethodTransform; -import org.sinytra.adapter.patch.api.MethodTransformBuilder; -import org.sinytra.adapter.patch.transformer.ModifyVarUpgradeToModifyExprVal; -import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; -import org.sinytra.adapter.patch.transformer.operation.unit.ExtractMixin; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionTarget; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMethodAccess; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMixinType; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -public class MethodTransformBuilderImpl> implements MethodTransformBuilder { - protected final List transforms = new ArrayList<>(); - - @Override - public T transformParams(Consumer consumer) { - TransformParameters.Builder builder = new TransformParameters.Builder(); - consumer.accept(builder); - return transform(builder.build()); - } - - @Override - public T modifyTarget(String... methods) { - return transform(new ModifyInjectionTarget(List.of(methods))); - } - - @Override - public T modifyMethodAccess(ModifyMethodAccess.AccessChange... changes) { - return transform(new ModifyMethodAccess(List.of(changes))); - } - - @Override - public T extractMixin(String targetClass) { - return improveModifyVar() - .transform(new ExtractMixin(targetClass)); - } - - @Override - public T improveModifyVar() { - return transform(ModifyVarUpgradeToModifyExprVal.INSTANCE); - } - - @Override - public T modifyMixinType(String newType, Consumer consumer) { - return transform(new ModifyMixinType(newType, consumer)); - } - - @Override - public T transform(MethodTransform transformer) { - this.transforms.add(transformer); - return coerce(); - } - - @Override - public T transformMethods(List transformers) { - transformers.forEach(this::transform); - return coerce(); - } - - @Override - public T chain(Consumer consumer) { - consumer.accept(coerce()); - return coerce(); - } - - @SuppressWarnings("unchecked") - private T coerce() { - return (T) this; - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/MockMixinRuntime.java b/definition/src/main/java/org/sinytra/adapter/patch/util/MockMixinRuntime.java index 45d84110..7e9a1c7d 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/MockMixinRuntime.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/util/MockMixinRuntime.java @@ -1,8 +1,8 @@ package org.sinytra.adapter.patch.util; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.PatchEnvironment; +import org.sinytra.adapter.patch.api.TargetPair; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.extensibility.IMixinConfig; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; @@ -59,7 +59,7 @@ public class MockMixinRuntime { } } - public static Target createMixinTarget(MethodContext.TargetPair pair) { + public static Target createMixinTarget(TargetPair pair) { ClassInfo info = ClassInfo.forName(pair.classNode().name); try { return (Target) TARGET_CTR.invoke(info, pair.classNode(), pair.methodNode()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java deleted file mode 100644 index e0ebfccd..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/PipelineLegacyMethodTransformer.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.sinytra.adapter.next; - -import com.mojang.logging.LogUtils; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.pipeline.PipelineExecutor; -import org.sinytra.adapter.next.type.MixinType; -import org.sinytra.adapter.next.type.MixinTypes; -import org.sinytra.adapter.patch.api.*; -import org.slf4j.Logger; - -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; - -/** - * Entrypoint hook for UTP in the old method transformer system - */ -public class PipelineLegacyMethodTransformer implements MethodTransform { - private static final Logger LOGGER = LogUtils.getLogger(); - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - if (methodContext.findCleanInjectionTarget() == null - || !methodContext.failsDirtyInjectionCheck() && methodContext.hasValidSlice(methodContext.findDirtyInjectionTarget()) - ) { - return Patch.Result.PASS; - } - - PatchAuditTrail.Match previousMatch = context.environment().auditTrail().getMatch(methodContext); - if (previousMatch != null && previousMatch != PatchAuditTrail.Match.NONE) { - return Patch.Result.PASS; - } - - String annotationInternalName = Type.getType(methodContext.methodAnnotation().getDesc()).getInternalName(); - MixinType mixinType = MixinTypes.getMixinType(annotationInternalName); - if (mixinType == null) { - return Patch.Result.PASS; - } - ClassTarget classTarget = ClassTarget.parse(methodContext.rawClassAnnotation()); - if (classTarget == null) { - return Patch.Result.PASS; - } - - LOGGER.debug(MIXINPATCH, "Considering method {}.{}", classNode.name, methodNode.name); - - PatchAuditTrail auditTrail = context.environment().auditTrail(); - auditTrail.recordResult(methodContext, PatchAuditTrail.Match.NONE); - - MixinContext mixinContext = new MixinContext(classNode, methodNode, methodContext); - PipelineExecutor pipeline = new PipelineExecutor(classTarget, mixinContext); - Patch.Result result = pipeline.execute(mixinType); - if (result != Patch.Result.PASS) { - auditTrail.recordResult(methodContext, PatchAuditTrail.Match.FULL); - return result; - } - - return Patch.Result.PASS; - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java index b0ccf524..3fbbb8a4 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java @@ -1,11 +1,12 @@ package org.sinytra.adapter.next.env; -import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; public final class ConfigurationTemplates { public static final PropertyContainerTemplate MIXIN_BASE = PropertyContainerTemplate.builder() .require(Keys.MIXIN_TYPE, Keys.TARGET_CLASS, Keys.TARGET_METHOD, Keys.PARAMETERS, Keys.RETURN_TYPE) + .keys(Keys.LOCALS) .build(); public static final PropertyContainerTemplate MIXIN_AT = MIXIN_BASE.extend() .require(Keys.TARGET_AT) diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java b/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java index 569ae9f2..b367f9aa 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java @@ -1,20 +1,27 @@ package org.sinytra.adapter.next.env; import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.next.env.ctx.MethodHelper; import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.PatchEnvironment; import org.sinytra.adapter.patch.fixes.TypeAdapter; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.provider.ClassLookup; +import java.util.List; + public class MixinContext implements RefMapper { + private final String mixinId; + private final ClassTarget classTarget; private final ClassNode classNode; private final MethodNode methodNode; private final MethodNode originalMethodNode; @@ -22,14 +29,37 @@ public class MixinContext implements RefMapper { private final MethodHelper methodHelper; private final MethodContext methodContext; - public MixinContext(ClassNode classNode, MethodNode methodNode, MethodContext methodContext) { + private final Resolvers resolvers = new Resolvers(); + private final Processors processors = new Processors(); + + public MixinContext(ClassTarget classTarget, ClassNode classNode, MethodNode methodNode, MethodContext methodContext) { + this.mixinId = classNode.name + "#" + methodNode.name + methodNode.desc; + + this.classTarget = classTarget; this.classNode = classNode; this.methodNode = methodNode; - this.methodHelper = new MethodHelper(this, methodContext.targetTypes()); + this.methodHelper = new MethodHelper(this, classTarget.getTypes()); this.methodContext = methodContext; this.originalMethodNode = AdapterUtil.copyMethod(this.methodNode); } + public String getMixinId() { + return this.mixinId; + } + + // TODO Move out + public Resolvers getResolvers() { + return resolvers; + } + + public Processors getProcessors() { + return processors; + } + + public ClassTarget classTarget() { + return this.classTarget; + } + public ClassNode classNode() { return this.classNode; } @@ -85,4 +115,12 @@ public boolean isStatic() { public MethodContext legacy() { return this.methodContext; } + + public List targetTypes() { + return this.classTarget.getTypes(); + } + + public PatchEnvironment environment() { + return patchContext().environment(); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/OrderedRegistry.java b/definition/src/next/java/org/sinytra/adapter/next/env/OrderedRegistry.java index a5191c16..4bdacc8e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/OrderedRegistry.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/OrderedRegistry.java @@ -22,7 +22,7 @@ public List getAll() { return this.instances; } - public void addBefore(Class type, U entry) { + public OrderedRegistry addBefore(Class type, U entry) { assertNotFrozen(); assertUnique(entry); @@ -30,9 +30,11 @@ public void addBefore(Class type, U entry) { int index = this.instances.indexOf(original); this.instances.add(index, entry); + + return this; } - public void addAfter(Class type, U entry) { + public OrderedRegistry addAfter(Class type, U entry) { assertNotFrozen(); assertUnique(entry); @@ -40,13 +42,14 @@ public void addAfter(Class type, U entry) { int index = this.instances.indexOf(original); this.instances.add(index + 1, entry); + + return this; } public T getOrThrow(Class type) { return Objects.requireNonNull(get(type), "Entry not found for type %s".formatted(type)); } - @SuppressWarnings("unchecked") public void add(U entry) { assertNotFrozen(); assertUnique(entry); @@ -54,6 +57,15 @@ public void add(U entry) { this.instances.add(entry); } + public OrderedRegistry addFirst(U entry) { + assertNotFrozen(); + assertUnique(entry); + + this.instances.addFirst(entry); + + return this; + } + @SuppressWarnings("unchecked") @Nullable public T get(Class type) { @@ -68,7 +80,7 @@ public T get(Class type) { @SuppressWarnings("unchecked") public void assertUnique(U entry) { if (get((Class) entry.getClass()) != null) { - throw new IllegalArgumentException("Duplicate entry for type %s".formatted(entry.getClass())); + throw new IllegalArgumentException("Duplicate entry for type %s".formatted(entry.getClass())); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java index 8976815a..6f8ed4bd 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java @@ -1,74 +1,64 @@ package org.sinytra.adapter.next.env.ann; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.next.pipeline.config.MutablePropertyContainer; +import org.sinytra.adapter.next.pipeline.config.PropertyContainer; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.config.PropertyKey; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import org.sinytra.adapter.patch.api.MixinConstants; import org.sinytra.adapter.patch.util.MethodQualifier; +import org.spongepowered.asm.mixin.injection.At; import java.util.Objects; import java.util.Optional; -import java.util.OptionalInt; - -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.*; public class AtData { - @NotNull - private final String value; - @Nullable - private final String target; - @Nullable - private final Integer ordinal; + public static final PropertyContainerTemplate TEMPLATE = PropertyContainerTemplate.builder() + .require(Keys.VALUE) + .keys(Keys.TARGET, Keys.ORDINAL, Keys.SHIFT, Keys.BY) + .build(); - public AtData(@NotNull String value, @Nullable MethodInsnNode target) { - this(value, target != null ? MethodQualifier.create(target) : null); - } + private final PropertyContainer properties; - public AtData(@NotNull String value, @Nullable MethodQualifier target) { - this(value, target != null ? target.asDescriptor() : null, null); + private AtData(PropertyContainer properties) { + this.properties = properties; } - public AtData(@NotNull String value, @Nullable String target, @Nullable Integer ordinal) { - this.value = Objects.requireNonNull(value, "Value must not be null"); - this.target = target; - this.ordinal = ordinal; + public Optional getProperty(PropertyKey key) { + return this.properties.getProperty(key); } public String getValue() { - return this.value; + return getProperty(Keys.VALUE).orElseThrow(); } public Optional getTarget() { - return Optional.ofNullable(this.target); + return getProperty(Keys.TARGET); } public String getTargetOrThrow() { - return Objects.requireNonNull(this.target, "No target specified"); + return getTarget().orElseThrow(); } - public OptionalInt getOrdinal() { - return this.ordinal != null ? OptionalInt.of(this.ordinal) : OptionalInt.empty(); + public Optional getOrdinal() { + return getProperty(Keys.ORDINAL); } + @SuppressWarnings({"rawtypes", "unchecked"}) public void apply(AnnotationHandle handle) { - handle.setOrAppendNonNull("value", this.value); - handle.setOrAppendNonNull("target", this.target); - if (this.ordinal != null) { - handle.setOrAppendNonNull("ordinal", this.ordinal); - } + this.properties.getProperties().forEach((key, value) -> { + Object serialized = ((PropertyKey) key).serialize(value); + handle.setOrAppendNonNull(key.name(), serialized); + }); } public AnnotationNode toAnnotationNode() { AnnotationNode node = new AnnotationNode(MixinConstants.AT); - node.visit(AT_VALUE, Objects.requireNonNull(this.value)); - node.visit(AT_TARGET, Objects.requireNonNull(this.target)); - if (this.ordinal != null) { - node.visit(PROPERTY_ORDINAL, this.ordinal); - } + this.properties.getProperties().forEach((key, value) -> node.visit(key.name(), value)); return node; } @@ -81,36 +71,88 @@ public AtData withTarget(MethodQualifier target) { } public AtData withTarget(String target) { - return new AtData(this.value, target, this.ordinal); + return withProperty(Keys.TARGET, target); } public AtData withOrdinal(Integer ordinal) { - return new AtData(this.value, target, ordinal); + return withProperty(Keys.ORDINAL, ordinal); + } + + public AtData withProperty(PropertyKey key, T value) { + MutablePropertyContainer copy = this.properties.copy(); + copy.setProperty(key, value); + return new AtData(copy); } @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; AtData atData = (AtData) o; - return Objects.equals(value, atData.value) && Objects.equals(target, atData.target) && Objects.equals(ordinal, atData.ordinal); + return Objects.equals(properties, atData.properties); } @Override public int hashCode() { - return Objects.hash(value, target, ordinal); + return Objects.hash(properties); } public static Optional parse(AnnotationHandle annotation, RefMapper mapper) { - String value = annotation.getValue("value").map(AnnotationValueHandle::get).orElse(null); - if (value == null) { - return Optional.empty(); + PropertyContainer container = MutablePropertyContainer.parse(annotation, TEMPLATE, mapper); + return Optional.ofNullable(container).map(AtData::new); + } + + public static AtData create(String value) { + return builder(value).build(); + } + + public static AtData create(String value, MethodInsnNode target) { + return create(value, MethodQualifier.create(target).asDescriptor()); + } + + public static AtData create(String value, @Nullable String target) { + Builder builder = builder(value); + if (value != null) { + builder.property(Keys.TARGET, target); + } + return builder.build(); + } + + public static Builder builder(String value) { + return new Builder(value); + } + + public static class Builder { + private final MutablePropertyContainer properties = MutablePropertyContainer.create(TEMPLATE); + + public Builder(String value) { + this.properties.setProperty(Keys.VALUE, value); + } + + public Builder target(String target) { + return property(Keys.TARGET, target); } - String target = annotation.getValue("target").map(AnnotationValueHandle::get) - .map(mapper::remap) - .orElse(null); - Integer ordinal = annotation.getValue("ordinal").map(AnnotationValueHandle::get).orElse(null); + public Builder ordinal(Integer ordinal) { + return property(Keys.ORDINAL, ordinal); + } + + public Builder property(PropertyKey key, T value) { + this.properties.setProperty(key, value); + return this; + } + + public AtData build() { + return new AtData(this.properties); + } + } - return Optional.of(new AtData(value, target, ordinal)); + public static class Keys { + public static final PropertyKey VALUE = PropertyKey.create("value", String.class); + public static final PropertyKey TARGET = PropertyKey.builder("target") + .parser((value, mapper) -> mapper.remap((String) value)) + .build(); + public static final PropertyKey ORDINAL = PropertyKey.create("ordinal", Integer.class); + public static final PropertyKey SHIFT = PropertyKey.create("shift", At.Shift.class); + public static final PropertyKey BY = PropertyKey.create("by", Integer.class); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java index d1c288e2..f5c1f6eb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java @@ -8,13 +8,39 @@ import java.util.List; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.MIXIN_TARGETS; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.MIXIN_VALUE; + public class ClassTarget { + private final AnnotationHandle handle; private final Either>, AnnotationValueHandle>> either; - public ClassTarget(Either>, AnnotationValueHandle>> either) { + public ClassTarget(AnnotationHandle handle, Either>, AnnotationValueHandle>> either) { + this.handle = handle; this.either = either; } + @Deprecated + public AnnotationHandle getHandle() { + return this.handle; + } + + @Deprecated + public AnnotationValueHandle getValueHandle() { + if (this.either.left().isPresent()) { + return this.either.left().orElseThrow(); + } + return this.either.right().orElseThrow(); + } + + public List getTypes() { + return this.either.map(AnnotationValueHandle::get, h -> h.get() + .stream() + .map(Type::getObjectType) + .toList() + ); + } + public Type getSingle() { List types = this.either.map(AnnotationValueHandle::get, h -> h.get() .stream() @@ -27,12 +53,18 @@ public Type getSingle() { return types.getFirst(); } + @Deprecated + public void set(Type type) { + this.either.ifLeft(h -> h.set(List.of(type))) + .ifRight(h -> h.set(List.of(type.getInternalName()))); + } + @Nullable public static ClassTarget parse(AnnotationHandle handle) { - return handle.>getValue("value") + return handle.>getValue(MIXIN_VALUE) .>, AnnotationValueHandle>>>map(Either::left) - .or(() -> handle.>getValue("targets").map(Either::right)) - .map(ClassTarget::new) + .or(() -> handle.>getValue(MIXIN_TARGETS).map(Either::right)) + .map(v -> new ClassTarget(handle, v)) .orElse(null); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java index 141980dd..205fa5ad 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java @@ -2,14 +2,28 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; +import java.util.List; +import java.util.Optional; +import java.util.OptionalDouble; + +// TODO Cleanup public class ConstantData { - private Object value; + private final Object value; - public ConstantData(Object value) { + private ConstantData(Object value) { this.value = value; } - + + public Optional classValue() { + return value instanceof Type t ? Optional.of(t) : Optional.empty(); + } + + public OptionalDouble doubleValue() { + return value instanceof Double d ? OptionalDouble.of(d) : OptionalDouble.empty(); + } + public static ConstantData classValue(Type value) { return new ConstantData(value); } @@ -17,8 +31,21 @@ public static ConstantData classValue(Type value) { public void apply(AnnotationHandle handle) { if (this.value instanceof Type) { handle.setOrAppendNonNull("classValue", this.value); + } else if (this.value instanceof Double) { + handle.setOrAppendNonNull("doubleValue", this.value); } else { throw new IllegalStateException("Unexpected value: " + value); } } + + public static Optional parse(AnnotationHandle handle) { + List knownKeys = List.of("doubleValue", "classValue"); + for (String key : knownKeys) { + Object value = handle.getValue(key).map(AnnotationValueHandle::get).orElse(null); + if (value != null) { + return Optional.of(new ConstantData(value)); + } + } + return Optional.empty(); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java index 75b8f423..7da76f08 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java @@ -1,10 +1,15 @@ package org.sinytra.adapter.next.env.ann; public class MixinAnnotationConstants { + public static final String MIXIN_VALUE = "value"; + public static final String MIXIN_TARGETS = "targets"; + public static final String AT_METHOD = "method"; public static final String AT_TARGET = "target"; public static final String AT_VALUE = "value"; public static final String AT_VAL_INVOKE = "INVOKE"; + public static final String AT_VAL_INVOKE_ASSIGN = "INVOKE_ASSIGN"; + public static final String AT_VAL_RETURN = "RETURN"; public static final String AT_VAL_STORE = "STORE"; public static final String AT_VAL_SINYTRA_INSTANCEOF = "sinytra:INSTANCEOF"; public static final String AT_SHIFT = "shift"; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java deleted file mode 100644 index 6899e0f1..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinData.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.sinytra.adapter.next.env.ann; - -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainer; -import org.sinytra.adapter.next.pipeline.config.PropertyKey; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.Optional; - -public class MixinData { - private final ClassTarget targetClass; - private final MethodQualifier targetMethod; - private final AtData atData; - private final PropertyContainer properties; - - public MixinData(ClassTarget targetClass, MethodQualifier targetMethod, AtData atData, PropertyContainer properties) { - this.targetClass = targetClass; - this.targetMethod = targetMethod; - this.atData = atData; - this.properties = properties; - } - - public String getTargetClass() { - return this.targetClass.getSingle().getInternalName(); - } - - public MethodQualifier getTargetMethod() { - return this.targetMethod; - } - - public AtData at() { - return this.atData; - } - - public Optional getProperty(PropertyKey key) { - return this.properties.getProperty(key); - } - - public boolean isCancellable() { - return getProperty(Configuration.Keys.CANCELLABLE).orElse(false); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/Auditor.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/Auditor.java new file mode 100644 index 00000000..b10323d4 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/Auditor.java @@ -0,0 +1,5 @@ +package org.sinytra.adapter.next.env.ctx; + +public interface Auditor { + void recordAudit(Object transform, String message, Object... args); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java index c700e433..1892a17c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java @@ -8,7 +8,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.patch.api.MethodContext.TargetPair; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.slf4j.Logger; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java index ef6080dc..50115cef 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java @@ -13,9 +13,8 @@ import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.MethodContext.TargetPair; import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.MockMixinRuntime; import org.sinytra.adapter.patch.util.provider.ClassLookup; @@ -77,25 +76,25 @@ public Pair> findOwnMethodsByName(ClassLookup lookup return this.methodFinder.findMethods(lookup, qualifier, MethodFinder.Flags.FALLBACK_OWNER | MethodFinder.Flags.IGNORE_DESC); } - public boolean hasInjectionTargetInsns(@Nullable MethodContext.TargetPair target) { + public boolean hasInjectionTargetInsns(@Nullable TargetPair target) { return !findInjectionTargetInsns(target).isEmpty(); } @Nullable - public AbstractInsnNode findInjectionTargetInsn(@Nullable MethodContext.TargetPair target) { + public AbstractInsnNode findInjectionTargetInsn(@Nullable TargetPair target) { List cleanInsns = findInjectionTargetInsns(target); return cleanInsns.size() != 1 ? null : cleanInsns.getFirst(); } - public List findInjectionTargetInsns(@Nullable MethodContext.TargetPair target) { + public List findInjectionTargetInsns(@Nullable TargetPair target) { return findInjectionTargetInsns(target, false); } - public List findInjectionTargetInsns(@Nullable MethodContext.TargetPair target, boolean ignoreOrdinal) { + public List findInjectionTargetInsns(@Nullable TargetPair target, boolean ignoreOrdinal) { return this.targetInstructionsCache.computeIfAbsent(target, t -> computeInjectionTargetInsns(t, ignoreOrdinal)); } - private List computeInjectionTargetInsns(@Nullable MethodContext.TargetPair target, boolean ignoreOrdinal) { + private List computeInjectionTargetInsns(@Nullable TargetPair target, boolean ignoreOrdinal) { return computeInjectionTargetInsns( target, this.context::injectionPointAnnotation, @@ -150,7 +149,7 @@ public List resolveCapturedMethodParams(Configuration clean, Configuration } @Nullable - private List computeInjectionTargetInsns(@Nullable MethodContext.TargetPair target, Supplier atNodeSupplier, BiFunction injectionPointParser, boolean ignoreShift) { + private List computeInjectionTargetInsns(@Nullable TargetPair target, Supplier atNodeSupplier, BiFunction injectionPointParser, boolean ignoreShift) { if (target == null) { return List.of(); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java index d4084b89..e46645d0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java @@ -33,6 +33,12 @@ public boolean hasAnnotation(String desc) { return this.annotations.stream() .anyMatch(annotation -> annotation.getDesc().equals(desc)); } + + public Builder extend() { + Builder builder = builder(this.type); + this.annotations.forEach(builder::annotate); + return builder; + } public static Parameter simple(Type type) { return new Parameter(type, List.of()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java index 6123aa75..2860624e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java @@ -6,7 +6,8 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.objectweb.asm.tree.analysis.*; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.SourceValue; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.selector.FrameUtil; diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java b/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java new file mode 100644 index 00000000..18b605fa --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java @@ -0,0 +1,33 @@ +package org.sinytra.adapter.next.flow; + +import org.sinytra.adapter.next.pipeline.PipelineMethodTransformer; +import org.sinytra.adapter.next.transform.FieldAccessorTypeTransformer; +import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.next.transform.cls.DynamicAnonClassIndexPatch; +import org.sinytra.adapter.next.transform.cls.DynamicAnonymousShadowFieldTypePatch; +import org.sinytra.adapter.next.transform.patch.MethodPatch; +import org.sinytra.adapter.next.transform.patch.MethodPatchTransformer; +import org.sinytra.adapter.next.transform.preprocess.CapturedLocalsPreProcessor; +import org.sinytra.adapter.next.transform.preprocess.LocalCaptureUpgradeTransformer; +import org.sinytra.adapter.next.transform.ClassTransformer; +import org.sinytra.adapter.patch.fixes.FieldTypeUsageTransformer; + +import java.util.List; + +public class DynamicPatches { + public static final List CLASS_PATCHES = List.of( + new DynamicAnonClassIndexPatch(), + new DynamicAnonymousShadowFieldTypePatch(), + new FieldTypeUsageTransformer() + ); + + public static List methodTransformers(List patches) { + return List.of( + new FieldAccessorTypeTransformer(), // Interface mixin only + new LocalCaptureUpgradeTransformer(), + new CapturedLocalsPreProcessor(), + new MethodPatchTransformer(patches), + new PipelineMethodTransformer() + ); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java b/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java new file mode 100644 index 00000000..2a898081 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java @@ -0,0 +1,103 @@ +package org.sinytra.adapter.next.flow; + +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.MethodNode; +import org.sinytra.adapter.next.env.ann.ClassTarget; +import org.sinytra.adapter.next.env.ctx.MethodHelper; +import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.next.pipeline.config.*; +import org.sinytra.adapter.next.type.MixinType; +import org.sinytra.adapter.next.type.MixinTypes; +import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchEnvironment; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class MixinParser { + + @Nullable + public static MixinClassHandle parseMixins(ClassNode classNode, PatchEnvironment environment) { + ClassTarget cls = parseTargetClass(classNode); + if (cls == null || cls.getTypes().size() > 1) return null; + + RefMapper refMapper = ref -> environment.refmapHolder().remap(classNode.name, ref); + List methods = new ArrayList<>(); + for (MethodNode method : classNode.methods) { + MixinMethodHandle handle = parseMixin(cls, method, refMapper); + if (handle != null) { + methods.add(handle); + } + } + + return new MixinClassHandle(cls, methods); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, RefMapper mapper) { + if (method.visibleAnnotations == null) return null; + + for (AnnotationNode annotation : method.visibleAnnotations) { + AnnotationHandle handle = new AnnotationHandle(annotation); + + String internalName = Type.getType(annotation.desc).getInternalName(); + MixinType mixinType = MixinTypes.getMixinType(internalName); + if (mixinType == null) continue; + + PropertyContainerTemplate template = mixinType.getConfigurationTemplate(); + Set> keys = template.getKeys(); + + MutablePropertyContainer properties = MutablePropertyContainer.create(template); + properties.setProperty(Keys.MIXIN_TYPE, annotation.desc); + properties.setProperty(Keys.TARGET_CLASS, cls.getSingle().getInternalName()); + properties.setProperty(Keys.RETURN_TYPE, Type.getReturnType(method.desc)); + + for (PropertyKey key : keys) { + if (properties.hasProperty(key)) continue; + + Object value = handle.getValue(key.name()).map(AnnotationValueHandle::get).orElse(null); + if (value == null) continue; + + if (key.parser() != null) { + Object parsed = key.parser().parse(value, mapper); + properties.setProperty(key, parsed); + } else { + throw new IllegalStateException("Cannot parse for key %s, it does not define a parser".formatted(key.name())); + } + } + + // Set static property + properties.setProperty(SpecialKeys.STATIC, MethodHelper.isStatic(method)); + + return new MixinMethodHandle(mixinType, method, handle, properties); + } + + return null; + } + + @Nullable + private static ClassTarget parseTargetClass(ClassNode classNode) { + if (classNode.invisibleAnnotations == null) return null; + + for (AnnotationNode annotation : classNode.invisibleAnnotations) { + if (annotation.desc.equals(MixinConstants.MIXIN)) { + AnnotationHandle ann = new AnnotationHandle(annotation); + return ClassTarget.parse(ann); + } + } + + return null; + } + + public record MixinMethodHandle(MixinType mixinType, MethodNode methodNode, AnnotationHandle methodAnnotation, PropertyContainer properties) { + } + + public record MixinClassHandle(ClassTarget classTarget, List mixins) { + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java b/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java new file mode 100644 index 00000000..32cf5b9f --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java @@ -0,0 +1,137 @@ +package org.sinytra.adapter.next.flow; + +import com.mojang.logging.LogUtils; +import org.objectweb.asm.tree.ClassNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.ClassTarget; +import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Keys; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.transform.ClassTransformer; +import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.next.type.MixinType; +import org.sinytra.adapter.patch.MethodContextImpl; +import org.sinytra.adapter.patch.PatchContextImpl; +import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.api.*; +import org.sinytra.adapter.patch.util.MethodQualifier; +import org.slf4j.Logger; + +import java.util.List; + +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; + +public class Patcher { + private static final Logger LOGGER = LogUtils.getLogger(); + + /* + Patcher phases: + - EARLY - Right after parsing, before preProcess is called + - AFTER_PRE - After preProcess is called + - VALIDATED - After clean config is validated + */ + + // TODO Support all known mixin types from PatchInstance (incl. interface mixins) + private final PatchEnvironment environment; + private final List classPatches; + private final List methodTransformers; + + public Patcher(PatchEnvironment environment, List classPatches, List methodTransformers) { + this.environment = environment; + this.classPatches = classPatches; + this.methodTransformers = methodTransformers; + } + + public PatchResult apply(ClassNode classNode) { + // 1. Parse mixin data + MixinParser.MixinClassHandle mixinClass = MixinParser.parseMixins(classNode, this.environment); + if (mixinClass == null) return PatchResult.PASS; + + ClassTarget classTarget = mixinClass.classTarget(); + PatchResult result = PatchResult.PASS; + PatchContextImpl context = new PatchContextImpl(classNode, classTarget.getTypes(), this.environment); + + // 2. Class-level transformations + for (ClassTransformer patch : this.classPatches) { + result = result.or(patch.apply(classNode, classTarget, context)); + } + + // 3. Mixin-level transformations + for (MixinParser.MixinMethodHandle mixin : mixinClass.mixins()) { + PatchResult subResult = processMixin(classNode, classTarget, context, mixin); + result = result.or(subResult); + } + + context.run(); + + return result; + } + + private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, PatchContext patchContext, MixinParser.MixinMethodHandle mixin) { + MethodQualifier target = mixin.properties().getProperty(Keys.TARGET_METHOD).orElse(null); + if (target == null) return PatchResult.PASS; + + MixinType mixinType = mixin.mixinType(); + MixinContext mixinContext = buildContext(classNode, classTarget, mixin, patchContext); + String mixinId = mixinContext.getMixinId(); + + // Build base config + PropertyContainerTemplate template = mixin.mixinType().getConfigurationTemplate(); + MutableConfiguration configuration = MutableConfiguration.create(template); + configuration.mergeFrom(mixin.properties()); + + // << RUN EARLY PHASE TODO + + // 1. Complete and validate clean config + TxResult preResult = mixinType.preProcess(mixinContext, configuration, mixinContext.getResolvers(), mixinContext.getProcessors()); + if (preResult == TxResult.FAIL) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed preProcess", mixinId); + return PatchResult.PASS; + } + + // Validate clean config + if (!configuration.validate()) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to invalid CLEAN config", mixinId); + return PatchResult.PASS; + } + + MethodContext legacy = mixinContext.legacy(); + PatchResult result = PatchResult.PASS; + // TODO Audit trail + if (!this.methodTransformers.isEmpty()) { + this.environment.auditTrail().prepareMethod(legacy); + } + + for (MethodTransformer transformer : this.methodTransformers) { + PatchResult txResult = transformer.apply(mixinContext, configuration); + result = result.or(txResult); + + /* + if (txResult == PatchResult.APPLY && this.environment.auditTrail().getMatch(legacy) == PatchAuditTrail.Match.FULL) { + break; + } + */ + } + + return result; + } + + private MixinContext buildContext(ClassNode classNode, ClassTarget classTarget, MixinParser.MixinMethodHandle mixin, PatchContext patchContext) { + AnnotationHandle handle = mixin.methodAnnotation().getNested(MixinAnnotationConstants.PROPERTY_AT) + .orElse(null); + + MethodContext legacyContext = MethodContextImpl.builder() + .classNode(classNode) + .rawClassAnnotation(classTarget.getHandle()) + .classAnnotation(classTarget.getValueHandle()) + .targetTypes(classTarget.getTypes()) + .methodNode(mixin.methodNode()) + .methodAnnotation(mixin.methodAnnotation()) + .injectionPointAnnotation(handle) + .build(patchContext); + + return new MixinContext(classTarget, classNode, mixin.methodNode(), legacyContext); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java deleted file mode 100644 index b211df21..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineExecutor.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.sinytra.adapter.next.pipeline; - -import com.mojang.logging.LogUtils; -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ann.MixinData; -import org.sinytra.adapter.next.pipeline.config.*; -import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.next.pipeline.resolver.Resolver.ResolutionResult; -import org.sinytra.adapter.next.pipeline.resolver.Resolver.ResultType; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.type.MixinType; -import org.sinytra.adapter.next.type.MixinTypes; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.slf4j.Logger; - -import java.util.Objects; -import java.util.Set; - -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; - -@SuppressWarnings({"rawtypes", "unchecked"}) -public class PipelineExecutor { - private static final Logger LOGGER = LogUtils.getLogger(); - - private final ClassTarget classTarget; - private final MixinContext context; - - public PipelineExecutor(ClassTarget classTarget, MixinContext context) { - this.classTarget = classTarget; - this.context = context; - } - - public Patch.Result execute(MixinType mixinType) { - MixinData data = parseMixinData(mixinType); - if (data == null) { - return Patch.Result.PASS; - } - String mixinId = this.context.classNode().name + "#" + this.context.methodNode().name + this.context.methodNode().desc; - - Resolvers resolvers = new Resolvers(); - Processors processors = new Processors(); - PropertyContainerTemplate template = Objects.requireNonNull(mixinType.getConfigurationTemplate()); - - // 1. Create clean config - ConfigurationImpl cleanConfig = new ConfigurationImpl(template); - cleanConfig.setMixinType(this.context.methodAnnotation().getDesc()); - cleanConfig.setTargetClass(data.getTargetClass()); - cleanConfig.setTargetMethod(data.getTargetMethod()); - cleanConfig.setAtData(data.at()); - cleanConfig.setReturnType(Type.getReturnType(context.methodNode().desc)); - - // 1.1. Create dirty config - MutableConfiguration dirtyConfig = new ConfigurationImpl(template, cleanConfig); - dirtyConfig.inheritMixinType(); - dirtyConfig.inheritTargetClass(); - - Recipe recipe = new Recipe(cleanConfig, dirtyConfig, resolvers, processors, this.context); - - // 2. Complete clean config - TxResult preResult = mixinType.preProcess(data, this.context, cleanConfig, recipe); - if (preResult == TxResult.FAIL) { - LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed preProcess", mixinId); - return Patch.Result.PASS; - } - - // 2.1. Validate clean config - if (!cleanConfig.validate()) { - LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to invalid CLEAN config", mixinId); - return Patch.Result.PASS; - } - - // 3. Run Resolvers - resolvers.freeze(); - for (Resolver resolver : resolvers.getAll()) { - ResolutionResult res = resolver.resolve(data, this.context, recipe); - Objects.requireNonNull(res, "BUG: Received null from resolver " + resolver.getClass()); - - if (res.type() == ResultType.SUCCESS || res.type() == ResultType.REPLACE) { - if (res.type() == ResultType.REPLACE) { - dirtyConfig = res.patch().copy(); - break; - } else { - dirtyConfig.mergeFrom(res.patch()); - } - } else if (res.type() == ResultType.FAIL) { - LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed RESOLVER {}", mixinId, resolver.getClass().getSimpleName()); - return Patch.Result.PASS; - } - } - - // 4. Complete dirty config - if (dirtyConfig.hasProperty(Configuration.Keys.MIXIN_TYPE)) { - String type = dirtyConfig.getMixinType(); - MixinType lateMixinType = MixinTypes.getMixinType(Type.getType(type).getInternalName()); - if (lateMixinType != null) { - TxResult postResult = lateMixinType.postProcess(data, this.context, cleanConfig, dirtyConfig, recipe); - if (postResult == TxResult.FAIL) { - LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed postProcess", mixinId); - return Patch.Result.PASS; - } - } - } - - // 4.1. Validate dirty config - if (!dirtyConfig.validate()) { - LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to invalid DIRTY config", mixinId); - return Patch.Result.PASS; - } - - // 5. Run Processors - processors.freeze(); - for (Processor processor : processors.getAll()) { - TxResult res = processor.process(data, this.context, dirtyConfig, recipe); - if (res == TxResult.FINALIZE) { - break; - } - if (res == TxResult.FAIL) { - LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed PROCESSOR {}", mixinId, processor.getClass().getSimpleName()); - return Patch.Result.PASS; - } - } - - return Patch.Result.APPLY; - } - - @Nullable - private MixinData parseMixinData(MixinType mixinType) { - AnnotationHandle atHandle = this.context.legacy().injectionPointAnnotation(); - if (atHandle == null) { - return null; - } - - AtData atData = AtData.parse(atHandle, this.context).orElse(null); - if (atData == null) { - return null; - } - - MethodQualifier targetMethod = this.context.legacy().getTargetMethodQualifier(); - AnnotationHandle methodHandle = this.context.legacy().methodAnnotation(); - - Set> keys = mixinType.requestProperties(); - BasePropertyContainer properties = new BasePropertyContainer(); - for (PropertyKey key : keys) { - Object value = methodHandle.getValue(key.name()).map(AnnotationValueHandle::get).orElse(null); - if (value == null) continue; - - if (key.parser() != null) { - Object parsed = key.parser().parse(value, this.context); - properties.setProperty(key, parsed); - } else { - throw new IllegalStateException("Cannot parse for key %s, it does not define a parser".formatted(key.name())); - } - } - - return new MixinData(this.classTarget, targetMethod, atData, properties); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java new file mode 100644 index 00000000..22001914 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java @@ -0,0 +1,130 @@ +package org.sinytra.adapter.next.pipeline; + +import com.mojang.logging.LogUtils; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.processor.Processor; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolver; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; +import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.next.type.MixinType; +import org.sinytra.adapter.next.type.MixinTypes; +import org.sinytra.adapter.patch.api.PatchAuditTrail; +import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.patch.api.TargetPair; +import org.slf4j.Logger; + +import java.util.Objects; + +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; + +public class PipelineMethodTransformer implements MethodTransformer { + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public PatchResult apply(MixinContext context, Configuration config) { + TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), config.getTargetMethod()); + if (cleanTarget == null) + return PatchResult.PASS; + + TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), config.getTargetMethod()); + if (!context.legacy().failsDirtyInjectionCheck() && context.legacy().hasValidSlice(dirtyTarget)) + return PatchResult.PASS; + + PatchAuditTrail.Match previousMatch = context.environment().auditTrail().getMatch(context.legacy()); + if (previousMatch != null && previousMatch != PatchAuditTrail.Match.NONE) + return PatchResult.PASS; + + String annotationInternalName = Type.getType(context.methodAnnotation().getDesc()).getInternalName(); + MixinType mixinType = MixinTypes.getMixinType(annotationInternalName); + if (mixinType == null) return PatchResult.PASS; + + ClassNode cls = context.classNode(); + LOGGER.debug(MIXINPATCH, "Considering method {}.{}", cls.name, cls.name); + + PatchAuditTrail auditTrail = context.environment().auditTrail(); + auditTrail.recordResult(context.legacy(), PatchAuditTrail.Match.NONE); + + PatchResult result = execute(context, config); + if (result != PatchResult.PASS) { + auditTrail.recordResult(context.legacy(), PatchAuditTrail.Match.FULL); + return result; + } + + return PatchResult.PASS; + } + + private PatchResult execute(MixinContext context, Configuration config) { + String mixinId = context.getMixinId(); + Resolvers resolvers = context.getResolvers(); + Processors processors = context.getProcessors(); + + // 1. Create clean config from validated config + MutableConfiguration cleanConfig = config.copy(); + + // 1.1. Create dirty config + MutableConfiguration dirtyConfig = cleanConfig.childConfig(); + dirtyConfig.inheritMixinType(); + dirtyConfig.inheritTargetClass(); + + Recipe recipe = new Recipe(cleanConfig, dirtyConfig, resolvers, processors, context); + + // 2. Run Resolvers + resolvers.freeze(); + for (Resolver resolver : resolvers.getAll()) { + Resolver.ResolutionResult res = resolver.resolve(context, recipe); + Objects.requireNonNull(res, "BUG: Received null from resolver " + resolver.getClass()); + + if (res.type() == Resolver.ResultType.SUCCESS || res.type() == Resolver.ResultType.REPLACE) { + if (res.type() == Resolver.ResultType.REPLACE) { + dirtyConfig = res.patch().copy(); + break; + } else { + dirtyConfig.mergeFrom(res.patch()); + } + } else if (res.type() == Resolver.ResultType.FAIL) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed RESOLVER {}", mixinId, resolver.getClass().getSimpleName()); + return PatchResult.PASS; + } + } + + // 3. Complete dirty config + if (dirtyConfig.hasProperty(Keys.MIXIN_TYPE)) { + String type = dirtyConfig.getMixinType(); + MixinType lateMixinType = MixinTypes.getMixinType(Type.getType(type).getInternalName()); + if (lateMixinType != null) { + TxResult postResult = lateMixinType.postProcess(context, cleanConfig, dirtyConfig, recipe); + if (postResult == TxResult.FAIL) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed postProcess", mixinId); + return PatchResult.PASS; + } + } + } + + // 3.1. Validate dirty config + if (!dirtyConfig.validate()) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to invalid DIRTY config", mixinId); + return PatchResult.PASS; + } + + // 4. Run Processors + processors.freeze(); + for (Processor processor : processors.getAll()) { + TxResult res = processor.process(context, dirtyConfig, recipe); + if (res == TxResult.FINALIZE) { + break; + } + if (res == TxResult.FAIL) { + LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed PROCESSOR {}", mixinId, processor.getClass().getSimpleName()); + return PatchResult.PASS; + } + } + + return PatchResult.APPLY; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java index 345cc051..31bf9656 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java @@ -1,10 +1,11 @@ package org.sinytra.adapter.next.pipeline; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.TargetPair; /** * Defines the initial and desired states, which include mixin method metadata and per-mixin-type variables. @@ -17,13 +18,18 @@ public Recipe withDirtyConfig(Configuration dirty) { return new Recipe(this.clean, dirty, this.resolvers, this.processors, this.context); } - public MethodContext.TargetPair getCleanTarget() { + public TargetPair getCleanTarget() { if (clean.getTargetMethod() == null) return null; return context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); } - public MethodContext.TargetPair getDirtyTarget() { + public TargetPair getDirtyTarget() { if (dirty.getTargetMethod() == null) return null; return context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); } + + public boolean hasInjectionPointValue(String value) { + AtData at = clean.getAtData(); + return at != null && value.equals(at.getValue()); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/TxResultInstance.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/TxResultInstance.java deleted file mode 100644 index 1b1001b9..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/TxResultInstance.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.sinytra.adapter.next.pipeline; - -import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.ConfigurationImpl; - -import java.util.Optional; -import java.util.function.Consumer; - -public record TxResultInstance(TxResult type, @Nullable Configuration patch) { - private static final TxResultInstance FAIL = new TxResultInstance(TxResult.FAIL, null); - private static final TxResultInstance PASS = new TxResultInstance(TxResult.PASS, null); - - public static TxResultInstance success(Configuration patch) { - return new TxResultInstance(TxResult.SUCCESS, patch); - } - - public static TxResultInstance success(Consumer consumer) { - Configuration patch = new ConfigurationImpl(); - consumer.accept(patch); - return new TxResultInstance(TxResult.SUCCESS, patch); - } - - public static TxResultInstance pass() { - return PASS; - } - - public static TxResultInstance fail() { - return FAIL; - } - - public Optional maybePatch() { - return Optional.ofNullable(this.patch); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java index 7a8eab6c..aa490650 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java @@ -2,9 +2,13 @@ import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.Nullable; +import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; public class BasePropertyContainer implements MutablePropertyContainer { @@ -20,20 +24,9 @@ public BasePropertyContainer(@Nullable PropertyContainerTemplate template) { this.template = template; } - @SuppressWarnings({"rawtypes", "unchecked"}) @Override public boolean validate() { - if (this.template != null && !this.template.validate(this)) { - return false; - } - - for (Map.Entry, Object> entry : this.properties.entrySet()) { - PropertyKey key = entry.getKey(); - if (!key.validate(entry.getValue())) { - return false; - } - } - return true; + return this.template == null || this.template.validate(this); } @Override @@ -50,7 +43,11 @@ public Optional getProperty(PropertyKey key) { @Override public MutablePropertyContainer setProperty(PropertyKey key, @Nullable T value) { - this.properties.put(key, value); + if (value != null) { + this.properties.put(key, value); + } else { + this.properties.remove(key); + } return this; } @@ -80,7 +77,42 @@ public MutablePropertyContainer mergeFrom(PropertyContainer other) { return this; } + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + BasePropertyContainer container = (BasePropertyContainer) o; + return Objects.equals(properties, container.properties) && Objects.equals(template, container.template); + } + + @Override + public int hashCode() { + return Objects.hash(properties, template); + } + protected MutablePropertyContainer createCopyImpl() { - return new BasePropertyContainer(); + return new BasePropertyContainer(this.template); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static MutablePropertyContainer parse(AnnotationHandle handle, @Nullable PropertyContainerTemplate template, RefMapper mapper) { + MutablePropertyContainer container = new BasePropertyContainer(template); + + for (PropertyKey key : template.getKeys()) { + Object value = handle.getValue(key.name()).map(AnnotationValueHandle::get).orElse(null); + if (value == null) continue; + + if (key.parser() != null) { + Object parsed = key.parser().parse(value, mapper); + container.setProperty(key, parsed); + } else { + throw new IllegalStateException("Cannot parse for key %s, it does not define a parser".formatted(key.name())); + } + } + + if (!container.validate()) { + return null; + } + + return container; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java index 3283a30e..d4b7c2fc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java @@ -1,17 +1,10 @@ package org.sinytra.adapter.next.pipeline.config; import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.MethodInsnNode; import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ConstantData; -import org.sinytra.adapter.next.env.ann.SliceData; import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.util.MethodQualifier; -import java.util.List; - public interface Configuration extends PropertyContainer { String getMixinType(); @@ -27,49 +20,13 @@ public interface Configuration extends PropertyContainer { boolean shouldDelete(); - MutableConfiguration subConfig(); - - MutableConfiguration subConfig(PropertyContainerTemplate template); - - MutableConfiguration copy(); - - final class Keys { - // Mixin meta - public static final PropertyKey MIXIN_TYPE = PropertyKey.create("mixin_type"); - public static final PropertyKey TARGET_CLASS = PropertyKey.create("target_class"); - public static final PropertyKey TARGET_METHOD = PropertyKey.create("target_method"); - public static final PropertyKey TARGET_AT = PropertyKey.create("target_at"); - public static final PropertyKey TARGET_CONSTANT = PropertyKey.create("target_constant"); - // Method - public static final PropertyKey PARAMETERS = PropertyKey.create("parameters"); - public static final PropertyKey RETURN_TYPE = PropertyKey.create("return_type"); - // Control - public static final PropertyKey DELETE = PropertyKey.create("delete"); + boolean isCancellable(); - // Mixin data - public static final PropertyKey CANCELLABLE = PropertyKey.create("cancellable", Boolean.class); - public static final PropertyKey INDEX = PropertyKey.create("index", Integer.class); - public static final PropertyKey ORDINAL = PropertyKey.create("ordinal", Integer.class); - public static final PropertyKey ARGS_ONLY = PropertyKey.create("argsOnly", Boolean.class); - public static final PropertyKey SLICE = PropertyKey.builder("slice") - .parser((value, mapper) -> SliceData.parse(new AnnotationHandle((AnnotationNode) value), mapper)) - .build(); - public static final PropertyKey> SLICES = PropertyKey.>builder("slice") - .parser((value, mapper) -> ((List) value).stream() - .map(AnnotationHandle::new) - .map(n -> SliceData.parse(n, mapper)) - .toList()) - .build(); + MutableConfiguration childConfig(); - private Keys() { - } - } + MutableConfiguration copyClean(); - final class SpecialKeys { - // Hidden - public static final PropertyKey EXTRACT_TARGET = PropertyKey.create("_extract_target_minsn"); + MutableConfiguration copyClean(PropertyContainerTemplate template); - private SpecialKeys() { - } - } + MutableConfiguration copy(); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java index 0070494b..d1eb7ca9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java @@ -16,10 +16,6 @@ public class ConfigurationImpl extends BasePropertyContainer implements MutableC @Nullable private final Configuration parent; - public ConfigurationImpl() { - this(null, null); - } - public ConfigurationImpl(@Nullable PropertyContainerTemplate template) { this(template, null); } @@ -68,7 +64,7 @@ public MutableConfiguration inheritParameters() { public MutableConfiguration inheritReturnType() { return inheritProperty(Keys.RETURN_TYPE); } - + @Override public MutableConfiguration inheritShouldDelete() { return inheritProperty(Keys.DELETE); @@ -110,6 +106,12 @@ public boolean shouldDelete() { return boxed != null && boxed.booleanValue(); } + @Override + public boolean isCancellable() { + Boolean boxed = getProperty(Keys.CANCELLABLE).orElse(null); + return boxed != null && boxed.booleanValue(); + } + @Override public MutableConfiguration setTargetClass(String targetClass) { setProperty(Keys.TARGET_CLASS, targetClass); @@ -191,22 +193,27 @@ private T getPropertyOrNull(PropertyKey key) { } @Override - public MutableConfiguration subConfig() { + public MutableConfiguration copyClean() { return new ConfigurationImpl(this.template, this.parent); } @Override - public MutableConfiguration subConfig(PropertyContainerTemplate template) { + public MutableConfiguration copyClean(PropertyContainerTemplate template) { return new ConfigurationImpl(template, this.parent); } @Override protected MutablePropertyContainer createCopyImpl() { - return subConfig(); + return copyClean(); } @Override public MutableConfiguration copy() { return (MutableConfiguration) super.copy(); } + + @Override + public MutableConfiguration childConfig() { + return new ConfigurationImpl(this.template, this); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java new file mode 100644 index 00000000..3a4bbe5a --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java @@ -0,0 +1,80 @@ +package org.sinytra.adapter.next.pipeline.config; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.ann.ConstantData; +import org.sinytra.adapter.next.env.ann.SliceData; +import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.util.MethodQualifier; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.List; + +@SuppressWarnings("unchecked") +public final class Keys { + // Mixin meta + public static final PropertyKey MIXIN_TYPE = PropertyKey.create("mixin_type"); + public static final PropertyKey TARGET_CLASS = PropertyKey.create("target_class"); + public static final PropertyKey TARGET_METHOD = PropertyKey.builder("method") + .parser((value, mapper) -> { + // Get method targets + List methodRefs = (List) value; + if (methodRefs.size() != 1) { + // We only support single method targets for now + return null; + } + // Resolve method reference + String reference = mapper.remap(methodRefs.getFirst()); + // Extract owner, name and desc using regex + return MethodQualifier.create(reference).orElse(null); + }) + .build(); + public static final PropertyKey TARGET_AT = PropertyKey.builder("at") + .parser((value, mapper) -> { + AnnotationNode node = parseSingle(value, AnnotationNode.class); + AnnotationHandle handle = new AnnotationHandle(node); + return AtData.parse(handle, mapper).orElse(null); + }) + .build(); + public static final PropertyKey TARGET_CONSTANT = PropertyKey.builder("constant") + .parser((value, mapper) -> { + AnnotationNode node = parseSingle(value, AnnotationNode.class); + AnnotationHandle handle = new AnnotationHandle(node); + return ConstantData.parse(handle).orElse(null); + }) + .build(); + // Method + public static final PropertyKey PARAMETERS = PropertyKey.create("parameters"); + public static final PropertyKey RETURN_TYPE = PropertyKey.create("return_type"); + // Control + public static final PropertyKey DELETE = PropertyKey.create("delete"); + + // Mixin data + public static final PropertyKey CANCELLABLE = PropertyKey.create("cancellable", Boolean.class); + public static final PropertyKey INDEX = PropertyKey.create("index", Integer.class); + public static final PropertyKey ORDINAL = PropertyKey.create("ordinal", Integer.class); + public static final PropertyKey ARGS_ONLY = PropertyKey.create("argsOnly", Boolean.class); + public static final PropertyKey SLICE = PropertyKey.builder("slice") + .parser((value, mapper) -> SliceData.parse(new AnnotationHandle((AnnotationNode) value), mapper)) + .build(); + public static final PropertyKey> SLICES = PropertyKey.>builder("slice") + .parser((value, mapper) -> ((List) value).stream() + .map(AnnotationHandle::new) + .map(n -> SliceData.parse(n, mapper)) + .toList()) + .build(); + public static final PropertyKey LOCALS = PropertyKey.create("locals", LocalCapture.class); + + private Keys() { + } + + @SuppressWarnings("rawtypes") + private static T parseSingle(Object obj, Class cls) { + if (obj instanceof List list) { + return list.size() == 1 ? (T) list.getFirst() : null; + } + return cls.isInstance(obj) ? (T) obj : null; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java index 66565786..5f9ccdac 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java @@ -1,9 +1,24 @@ package org.sinytra.adapter.next.pipeline.config; import org.jetbrains.annotations.Nullable; +import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; public interface MutablePropertyContainer extends PropertyContainer { + static MutablePropertyContainer create() { + return create(null); + } + + static MutablePropertyContainer create(@Nullable PropertyContainerTemplate template) { + return new BasePropertyContainer(template); + } + + static MutablePropertyContainer parse(AnnotationHandle handle, @Nullable PropertyContainerTemplate template, RefMapper mapper) { + return BasePropertyContainer.parse(handle, template, mapper); + } + MutablePropertyContainer setProperty(PropertyKey key, @Nullable T value); + MutablePropertyContainer removeProperty(PropertyKey key); MutablePropertyContainer mergeFrom(PropertyContainer other); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java index 81b21a11..355a2a8d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java @@ -1,18 +1,27 @@ package org.sinytra.adapter.next.pipeline.config; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.stream.Stream; public class PropertyContainerTemplate { + private final Set> keys; private final List constraints; - private PropertyContainerTemplate(List constraints) { + private PropertyContainerTemplate(Set> keys, List constraints) { + this.keys = ImmutableSet.copyOf(keys); this.constraints = ImmutableList.copyOf(constraints); } + public Set> getKeys() { + return this.keys; + } + public boolean validate(PropertyContainer container) { for (Validator constraint : this.constraints) { if (!constraint.validate(container)) { @@ -23,7 +32,7 @@ public boolean validate(PropertyContainer container) { } public Builder extend() { - return new Builder(this.constraints); + return new Builder(this.keys, this.constraints); } public static Builder builder() { @@ -31,21 +40,31 @@ public static Builder builder() { } public static class Builder { + private final Set> keys; private final List constraints; public Builder() { + this.keys = new HashSet<>(); this.constraints = new ArrayList<>(); } - public Builder(List constraints) { + public Builder(Set> keys, List constraints) { + this.keys = new HashSet<>(keys); this.constraints = new ArrayList<>(constraints); } + public Builder keys(PropertyKey... keys) { + this.keys.addAll(List.of(keys)); + return this; + } + public Builder require(PropertyKey... keys) { + keys(keys); return addConstraint(c -> Stream.of(keys).allMatch(c::hasProperty)); } public Builder requireOne(PropertyKey... keys) { + keys(keys); return addConstraint(c -> Stream.of(keys) .filter(c::hasProperty) .count() == 1); @@ -57,7 +76,7 @@ public Builder addConstraint(Validator validator) { } public PropertyContainerTemplate build() { - return new PropertyContainerTemplate(this.constraints); + return new PropertyContainerTemplate(this.keys, this.constraints); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java index 657fab9b..d91abbf3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java @@ -5,21 +5,18 @@ import org.sinytra.adapter.next.env.ctx.RefMapper; import java.util.Objects; -import java.util.function.Predicate; public class PropertyKey { private final String name; - private final Predicate predicate; + @Nullable private final Parser parser; + @Nullable + private final Serializer serializer; - public PropertyKey(String name, @Nullable Predicate predicate, @Nullable Parser parser) { + public PropertyKey(String name, @Nullable Parser parser, @Nullable Serializer serializer) { this.name = Objects.requireNonNull(name); - this.predicate = Objects.requireNonNullElseGet(predicate, () -> x -> true); this.parser = parser; - } - - public boolean validate(T value) { - return this.predicate.test(value); + this.serializer = serializer; } public String name() { @@ -29,6 +26,14 @@ public String name() { public Parser parser() { return this.parser; } + + public Serializer serializer() { + return this.serializer; + } + + public Object serialize(T value) { + return this.serializer == null ? value : this.serializer.serialize(value); + } @Override public String toString() { @@ -40,44 +45,61 @@ public String toString() { public static PropertyKey create(String name) { return new PropertyKey<>(name, null, null); } - + public static PropertyKey create(String name, Class type) { return PropertyKey.builder(name).parseAs(type).build(); } - + public static Builder builder(String name) { return new Builder<>(name); } - + public interface Parser { + @Nullable T parse(Object value, RefMapper mapper); - } + } + + public interface Serializer { + @Nullable + Object serialize(T value); + } public static class Builder { private final String name; - private Predicate predicate; private Parser parser; + private Serializer serializer; public Builder(String name) { this.name = name; } - public Builder predicate(Predicate predicate) { - this.predicate = predicate; - return this; - } - + @SuppressWarnings({"unchecked", "rawtypes"}) public Builder parseAs(Class type) { - return parser((value, context) -> type.cast(value)); + if (type.isEnum()) { + return parser((value, mapper) -> { + String enumValue = ((String[]) value)[1]; + return (T) Enum.valueOf((Class) type, enumValue); + }) + .serializer(value -> { + String name = ((Enum) value).name(); + return new String[] { type.descriptorString(), name }; + }); + } + return parser((value, mapper) -> type.cast(value)); } - + public Builder parser(Parser parser) { this.parser = parser; return this; } + public Builder serializer(Serializer serializer) { + this.serializer = serializer; + return this; + } + public PropertyKey build() { - return new PropertyKey<>(this.name, this.predicate, this.parser); + return new PropertyKey<>(this.name, this.parser, this.serializer); } } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/SpecialKeys.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/SpecialKeys.java new file mode 100644 index 00000000..7dfd45ce --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/SpecialKeys.java @@ -0,0 +1,16 @@ +package org.sinytra.adapter.next.pipeline.config; + +import org.objectweb.asm.commons.InstructionAdapter; +import org.objectweb.asm.tree.MethodInsnNode; + +import java.util.function.Consumer; + +public final class SpecialKeys { + // Hidden + public static final PropertyKey EXTRACT_TARGET = PropertyKey.create("_extract_target_minsn"); + public static final PropertyKey> REDIRECT_ADAPTER = PropertyKey.create("_redirect_adapter"); + public static final PropertyKey STATIC = PropertyKey.create("_static"); + + private SpecialKeys() { + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/DisableMixinProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/DisableMixinProcessor.java index 0f9a4e13..804b5af0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/DisableMixinProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/DisableMixinProcessor.java @@ -1,18 +1,18 @@ package org.sinytra.adapter.next.pipeline.processor; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; public class DisableMixinProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (!dirty.shouldDelete()) { return TxResult.PASS; } + // methodContext.recordAudit(this, "Remove mixin method"); context.patchContext().postApply(() -> context.classNode().methods.remove(context.methodNode())); return TxResult.FINALIZE; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java index f62519ae..d3690984 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java @@ -3,17 +3,16 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.ConstantData; import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.patch.api.MixinConstants; public class InjectionTargetProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (!dirty.hasProperty(Keys.TARGET_AT) && !dirty.hasProperty(Keys.TARGET_CONSTANT)) { return TxResult.PASS; } @@ -33,6 +32,8 @@ public TxResult process(MixinData mixin, MixinContext context, Configuration dir } else { annotation.removeValues(MixinAnnotationConstants.PROPERTY_CONSTANT); } + + // methodContext.recordAudit(this, "Change injection point to %s", this.target); return TxResult.SUCCESS; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinTypeProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinTypeProcessor.java index f622656c..390dd02f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinTypeProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinTypeProcessor.java @@ -3,7 +3,6 @@ import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; @@ -12,13 +11,13 @@ public class MixinTypeProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { - if (recipe.clean().getMixinType().equals(dirty.getMixinType())) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { + if (recipe.clean().getMixinType().equals(dirty.getMixinType())) return TxResult.PASS; - } MethodNode methodNode = context.methodNode(); AnnotationHandle annotation = context.methodAnnotation(); + for (int i = 0; i < methodNode.visibleAnnotations.size(); i++) { AnnotationNode methodAnn = methodNode.visibleAnnotations.get(i); if (methodAnn == annotation.unwrap()) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java index e1501d56..01f2b6d9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java @@ -4,7 +4,6 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.VarInsnNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; @@ -12,8 +11,7 @@ import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformTarget; +import org.sinytra.adapter.patch.api.PatchResult; import java.util.List; import java.util.Map; @@ -21,7 +19,7 @@ public class ParametersProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { MethodParameters cleanParams = recipe.clean().getParameters(); MethodParameters dirtyParams = dirty.getParameters(); if (dirtyParams == null) return TxResult.FAIL; @@ -58,9 +56,9 @@ public TxResult process(MixinData mixin, MixinContext context, Configuration dir private boolean applyDiff(List clean, List dirty, MixinContext context, int offset) { ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(clean, dirty); if (!diff.isEmpty()) { - Patch.Result result = diff.offset(offset).asParameterTransformer(ParamTransformTarget.ALL, false, Set.of()) + PatchResult result = diff.offset(offset).asParameterTransformer(false, Set.of()) .apply(context.legacy()); - return result != Patch.Result.PASS; + return result != PatchResult.PASS; } return true; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java index 419807f7..f7a51af0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java @@ -1,11 +1,10 @@ package org.sinytra.adapter.next.pipeline.processor; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; public interface Processor { - TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe); + TxResult process(MixinContext context, Configuration dirty, Recipe recipe); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java index 58f3da1f..47391074 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java @@ -18,5 +18,6 @@ private void registerDefaultProcessors() { add(new ParametersProcessor()); add(new ReturnTypeProcessor()); add(new PropertyProcessor()); + add(new StaticAccessProcessor()); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java index 0062d012..9c735564 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java @@ -1,18 +1,17 @@ package org.sinytra.adapter.next.pipeline.processor; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.ORDINAL; -import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.SLICE; +import static org.sinytra.adapter.next.pipeline.config.Keys.ORDINAL; +import static org.sinytra.adapter.next.pipeline.config.Keys.SLICE; public class PropertyProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (dirty.getAtData() == null) return TxResult.FAIL; // TODO Auto append all props diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java index f51fbe9a..b235f830 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java @@ -7,7 +7,6 @@ import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; @@ -20,7 +19,7 @@ public class ReturnTypeProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { Type cleanType = recipe.clean().getReturnType(); Type dirtyType = dirty.getReturnType(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/StaticAccessProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/StaticAccessProcessor.java new file mode 100644 index 00000000..6a43c902 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/StaticAccessProcessor.java @@ -0,0 +1,62 @@ +package org.sinytra.adapter.next.pipeline.processor; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.MethodHelper; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.SpecialKeys; + +public class StaticAccessProcessor implements Processor { + @Override + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { + if (!recipe.clean().hasProperty(SpecialKeys.STATIC) || !dirty.hasProperty(SpecialKeys.STATIC)) + return TxResult.PASS; + + boolean cleanStatic = recipe.clean().getProperty(SpecialKeys.STATIC).orElseThrow(); + boolean dirtyStatic = recipe.dirty().getProperty(SpecialKeys.STATIC).orElseThrow(); + if (cleanStatic == dirtyStatic) return TxResult.PASS; + + MethodNode method = context.methodNode(); + boolean actuallyStatic = MethodHelper.isStatic(context.methodNode()); + // Add static + if (!actuallyStatic && !cleanStatic && dirtyStatic) { + // context.recordAudit(this, "Adding access modifier %s", change.modifier); + method.access |= Opcodes.ACC_STATIC; + + return TxResult.SUCCESS; + } + // Remove static + else if (actuallyStatic && cleanStatic && !dirtyStatic) { + // context.recordAudit(this, "Removing access modifier %s", change.modifier); + method.access &= ~Opcodes.ACC_STATIC; + + LocalVariableNode firstParam = method.localVariables.stream().filter(lvn -> lvn.index == 0) + .findFirst() + .orElseThrow(); + // Offset everything by 1 + for (LocalVariableNode lvn : method.localVariables) { + lvn.index++; + } + for (AbstractInsnNode insn : method.instructions) { + if (insn instanceof VarInsnNode varInsn) { + varInsn.var++; + } + } + + // Insert instance local variable + method.localVariables.add(new LocalVariableNode("this", Type.getObjectType(context.classNode().name).getDescriptor(), null, firstParam.start, firstParam.end, 0)); + + // TODO Must compute frames + return TxResult.SUCCESS; + } + + return TxResult.PASS; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java index 4cef3955..a40ca273 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java @@ -2,11 +2,11 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.api.LocalVariable; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.util.AdapterUtil; @@ -16,7 +16,7 @@ public class TargetMethodProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (dirty.getTargetMethod() == null) return TxResult.FAIL; context.methodAnnotation() @@ -34,7 +34,7 @@ private static void upgradeCapturedLocals(MethodNode methodNode, MethodContext m return; } - List availableLocals = methodContext.getTargetMethodLocals(capturedLocals.target()); + List availableLocals = methodContext.getTargetMethodLocals(capturedLocals.target()); // For now, only handle cases where all locals are part of the method's params, convenient when switching the target to a lambda if (availableLocals == null || !availableLocals.isEmpty()) { return; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ExtractMixin.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixin.java similarity index 86% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ExtractMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixin.java index c62270bf..389709b6 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/unit/ExtractMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.operation.unit; +package org.sinytra.adapter.next.pipeline.processor.extract; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -8,7 +8,10 @@ import org.objectweb.asm.tree.*; 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.api.MethodContext; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.PatchResult; import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -18,18 +21,13 @@ import java.util.function.Consumer; import java.util.stream.IntStream; -public record ExtractMixin(String targetClass, boolean remove) implements MethodTransform { - public ExtractMixin(String targetClass) { - this(targetClass, true); +// TODO Move to processor +public record ExtractMixin(String targetClass) { + public PatchResult apply(MethodContext methodContext) { + return apply(methodContext.getMixinClass(), methodContext.getMixinMethod(), methodContext, methodContext.patchContext()); } - @Override - public Collection getAcceptedAnnotations() { - return Set.of(MixinConstants.WRAP_WITH_CONDITION, MixinConstants.WRAP_OPERATION, MixinConstants.MODIFY_CONST, MixinConstants.MODIFY_ARG, MixinConstants.INJECT, MixinConstants.REDIRECT, MixinConstants.MODIFY_VAR, MixinConstants.MODIFY_EXPR_VAL); - } - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { // Sanity check boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC; @@ -37,7 +35,7 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont boolean isInherited = context.environment().inheritanceHandler().isClassInherited(this.targetClass, owner); Candidates candidates = findCandidates(classNode, methodNode); if (!candidates.canMove(classNode, isInherited)) { - return Patch.Result.PASS; + return PatchResult.PASS; } ClassNode targetClass = context.environment().dirtyClassLookup().getClass(this.targetClass).orElse(null); @@ -47,36 +45,26 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont // Add mixin methods from original to generated class for (MethodNode method : candidates.methods()) { - MethodNode transfer; - if (this.remove) { - transfer = method; - } else { - transfer = new MethodNode(method.access, method.name, method.desc, method.signature, method.exceptions == null ? null : method.exceptions.toArray(new String[0])); - method.accept(transfer); - } - - generatedTarget.methods.add(transfer); - updateOwnerRefereces(transfer, classNode, this.targetClass); - if (!isStatic && transfer.localVariables != null) { - transfer.localVariables.stream().filter(l -> l.index == 0).findFirst().ifPresent(lvn -> lvn.desc = Type.getObjectType(generatedTarget.name).getDescriptor()); + generatedTarget.methods.add(method); + updateOwnerRefereces(method, classNode, this.targetClass); + if (!isStatic && method.localVariables != null) { + method.localVariables.stream().filter(l -> l.index == 0).findFirst().ifPresent(lvn -> lvn.desc = Type.getObjectType(generatedTarget.name).getDescriptor()); } } candidates.handleUpdates().forEach(c -> c.accept(generatedTarget)); // Take care of captured locals - Patch.Result result = Patch.Result.PASS; + PatchResult result = PatchResult.PASS; if (methodContext.methodAnnotation().getValue("locals").isPresent()) { result = result.or(recreateLocalVariables(classNode, methodNode, methodContext, context, generatedTarget)); } methodContext.recordAudit(this, "Extract mixin to target %s", this.targetClass); // Remove original method - if (this.remove) { - methodContext.recordAudit(this, "Remove original method"); - context.postApply(() -> classNode.methods.removeAll(candidates.methods)); - } - return result.or(Patch.Result.APPLY); + methodContext.recordAudit(this, "Remove original method"); + context.postApply(() -> classNode.methods.removeAll(candidates.methods)); + return result.or(PatchResult.APPLY); } record Candidates(List methods, List> handleUpdates) { @@ -245,10 +233,10 @@ private static int fixAccess(int access) { * } * } */ - private static Patch.Result recreateLocalVariables(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, ClassNode extractClass) { + private static PatchResult recreateLocalVariables(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, ClassNode extractClass) { AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(methodNode, methodContext); if (capturedLocals == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } LocalVariableLookup table = capturedLocals.lvt(); int paramLocalStart = capturedLocals.paramLocalStart(); @@ -260,9 +248,9 @@ private static Patch.Result recreateLocalVariables(ClassNode classNode, MethodNo LocalVariableLookup targetTable = usage.targetTable(); Int2ObjectMap varInsnLists = usage.varInsnLists(); Int2IntMap usageCount = usage.usageCount(); - Patch.Result result = transform.remover().apply(classNode, methodNode, methodContext, context); - if (result == Patch.Result.PASS) { - return Patch.Result.PASS; + PatchResult result = transform.remover().apply(classNode, methodNode, methodContext, context); + if (result == PatchResult.PASS) { + return PatchResult.PASS; } // Create a copy of the method to call @@ -277,9 +265,9 @@ private static Patch.Result recreateLocalVariables(ClassNode classNode, MethodNo .sorted(Collections.reverseOrder()) .forEach(b::remove)) .build(); - Patch.Result cleanupResult = cleanupPatch.apply(classNode, methodNode, methodContext, context); - if (cleanupResult == Patch.Result.PASS) { - return Patch.Result.PASS; + PatchResult cleanupResult = cleanupPatch.apply(classNode, methodNode, methodContext, context); + if (cleanupResult == PatchResult.PASS) { + return PatchResult.PASS; } // Save reused variables. Locals that are only referenced once will be inlined instead @@ -358,6 +346,6 @@ private static Patch.Result recreateLocalVariables(ClassNode classNode, MethodNo methodNode.instructions = replacementInsns; extractClass.methods.add(copy); - return Patch.Result.COMPUTE_FRAMES; + return PatchResult.COMPUTE_FRAMES; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java index dde71a01..b5572ea8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java @@ -2,25 +2,24 @@ import org.objectweb.asm.tree.MethodInsnNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.SpecialKeys; import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.transformer.operation.unit.ExtractMixin; +import org.sinytra.adapter.patch.api.PatchResult; public class ExtractMixinProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (recipe.clean().getTargetClass().equals(dirty.getTargetClass())) return TxResult.PASS; - Patch.Result result = new ExtractMixin(dirty.getTargetClass()).apply(context.legacy()); - if (result == Patch.Result.PASS && dirty.hasProperty(Configuration.SpecialKeys.EXTRACT_TARGET)) { - MethodInsnNode minsn = dirty.getProperty(Configuration.SpecialKeys.EXTRACT_TARGET).orElseThrow(); + PatchResult result = new ExtractMixin(dirty.getTargetClass()).apply(context.legacy()); + if (result == PatchResult.PASS && dirty.hasProperty(SpecialKeys.EXTRACT_TARGET)) { + MethodInsnNode minsn = dirty.getProperty(SpecialKeys.EXTRACT_TARGET).orElseThrow(); result = new MirrorableExtractMixin(dirty.getTargetClass(), minsn).apply(context.legacy()); } - if (result == Patch.Result.PASS) { + if (result == PatchResult.PASS) { return TxResult.FAIL; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java index f313085e..dac911c4 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java @@ -7,8 +7,9 @@ import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.api.*; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyInjectionTarget; +import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -18,9 +19,11 @@ import java.util.List; import java.util.stream.Stream; -public record MirrorableExtractMixin(String destinationClass, MethodInsnNode destinationMethodInvocation) implements MethodTransform { - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_METHOD; + +// TODO Cleanup +public record MirrorableExtractMixin(String destinationClass, MethodInsnNode destinationMethodInvocation) { + public PatchResult apply(MethodContext methodContext) { Type selfType = Type.getObjectType(methodContext.findDirtyInjectionTarget().classNode().name); Type[] params = Type.getArgumentTypes(this.destinationMethodInvocation.desc); int selfIndex = Stream.of(Stream.iterate(0, i -> i < params.length, i -> i + 1) @@ -31,16 +34,16 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont .findFirst() .orElse(-1); if (selfIndex == -1) { - return Patch.Result.PASS; + return PatchResult.PASS; } List callInsns = MethodCallAnalyzer.getMethodCallSrcInsns(methodContext.findDirtyInjectionTarget().methodNode(), this.destinationMethodInvocation); if (callInsns == null || callInsns.size() <= selfIndex) { - return Patch.Result.PASS; + return PatchResult.PASS; } AbstractInsnNode selfParamInsn = callInsns.get(selfIndex); if (!(selfParamInsn instanceof VarInsnNode varInsn) || varInsn.getOpcode() != Opcodes.ALOAD || varInsn.var != 0) { - return Patch.Result.PASS; + return PatchResult.PASS; } // Cool, out instance is passed into the method. Now let's inject there and call the old mixin method ClassNode generatedTarget = methodContext.patchContext().environment().classGenerator().getOrGenerateMixinClass(methodContext.getMixinClass(), this.destinationClass, null); @@ -52,15 +55,15 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont List newParams = ImmutableList.builder().add(Type.getArgumentTypes(this.destinationMethodInvocation.desc)).add(MixinConstants.CI_TYPE).build(); // Make sure we have all required params if (!new HashSet<>(newParams).containsAll(originalParams)) { - return Patch.Result.PASS; + return PatchResult.PASS; } String desc = Type.getMethodDescriptor(Type.VOID_TYPE, newParams.toArray(Type[]::new)); // Change target - Patch.Result result = new ModifyInjectionTarget(List.of(MethodQualifier.create(destinationMethodInvocation).asDescriptor())).apply(methodContext); - if (result == Patch.Result.PASS) { - return Patch.Result.PASS; - } + methodContext.methodAnnotation() + .setOrAppendNonNull(AT_METHOD, List.of( + MethodQualifier.create(destinationMethodInvocation).asDescriptor() + )); MethodNode invokerMixinMethod = (MethodNode) generatedTarget.visitMethod(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, name, desc, null, null); invokerMixinMethod.visibleAnnotations = new ArrayList<>(originalMixinMethod.visibleAnnotations); @@ -80,6 +83,6 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont gen.returnValue(); gen.newLabel(); gen.endMethod(); - return Patch.Result.APPLY; + return PatchResult.APPLY; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java new file mode 100644 index 00000000..cd00703a --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java @@ -0,0 +1,57 @@ +package org.sinytra.adapter.next.pipeline.processor.redirect; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.commons.InstructionAdapter; +import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.SpecialKeys; +import org.sinytra.adapter.next.pipeline.processor.Processor; +import org.sinytra.adapter.patch.util.MethodQualifier; + +import java.util.function.Consumer; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; + +public class DivertRedirectProcessor implements Processor { + @Override + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { + Consumer patcher = dirty.getProperty(SpecialKeys.REDIRECT_ADAPTER).orElse(null); + if (patcher == null) return TxResult.PASS; + + if (!recipe.hasInjectionPointValue(AT_VAL_INVOKE)) return TxResult.PASS; + MethodQualifier target = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); + + if (target != null) { + MethodNode methodNode = context.methodNode(); + boolean applied = false; + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof MethodInsnNode minsn && target.matches(minsn)) { + for (AbstractInsnNode previous = insn.getPrevious(); previous != null; previous = previous.getPrevious()) { + if (previous instanceof LabelNode) { + MethodNode dummy = new MethodNode(); + InstructionAdapter adapter = new InstructionAdapter(dummy); + + LabelNode gotoTarget = new LabelNode(); + dummy.instructions.add(gotoTarget); + + patcher.accept(adapter); + + methodNode.instructions.insert(minsn, dummy.instructions); + methodNode.instructions.insert(previous, new JumpInsnNode(Opcodes.GOTO, gotoTarget)); + applied = true; + break; + } + } + } + } + if (applied) { + return TxResult.SUCCESS; + } + } + + return TxResult.PASS; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java similarity index 86% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java rename to definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java index 9492821e..d8483d31 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParameterUsageProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java @@ -1,17 +1,17 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.next.pipeline.processor.redirect; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.processor.Processor; import org.sinytra.adapter.patch.util.MethodQualifier; public class ParameterUsageProcessor implements Processor { @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { String cleanTarget = recipe.clean().getAtData().getTarget().orElse(null); if (cleanTarget == null) return TxResult.PASS; String dirtyTarget = dirty.getAtData().getTarget().orElse(null); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java index 6581204b..eb8d1315 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java @@ -6,7 +6,6 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.SourceValue; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.patch.analysis.selector.FrameUtil; import org.sinytra.adapter.patch.util.AdapterUtil; @@ -61,7 +60,6 @@ public static List> groupArrayInitializers(MethodNode met for (int i = 0; i <= maxIndex; i++) { AbstractInsnNode endNode = indexToStoreNode.get(i); - List currentGroup = new ArrayList<>(); if (endNode != null) { @@ -90,6 +88,7 @@ private static Integer resolveConstantIndex(SourceValue source) { return index; } } - return null; // Could not resolve to a static constant + // Could not resolve to a static constant + return null; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java index 29f76757..9c3cbdcf 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java @@ -5,7 +5,6 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.Parameter; import org.sinytra.adapter.next.pipeline.Recipe; @@ -27,7 +26,7 @@ public class WrapOpParamsProcessor implements Processor { private static final MethodQualifier WO_ORIGINAL_CALL = new MethodQualifier("Lcom/llamalad7/mixinextras/injector/wrapoperation/Operation;", "call", "([Ljava/lang/Object;)Ljava/lang/Object;"); @Override - public TxResult process(MixinData mixin, MixinContext context, Configuration dirty, Recipe recipe) { + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (dirty.getParameters() == null) return TxResult.FAIL; // Find original.call(...) diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java index 5e43de12..8c7f2847 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java @@ -2,7 +2,6 @@ import org.jetbrains.annotations.Nullable; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; @@ -22,7 +21,7 @@ public CompoundResolver addSubResolver(SubResolver subResolver) { return this; } - protected abstract boolean canApply(MixinData mixin, Recipe recipe); + protected abstract boolean canApply(Recipe recipe); @Nullable protected Configuration tryReuse(MixinContext context, Recipe recipe) { @@ -35,8 +34,8 @@ protected Configuration useFallback(MixinContext context, Recipe recipe) { } @Override - public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe) { - if (!canApply(mixin, recipe)) { + public ResolutionResult resolve(MixinContext context, Recipe recipe) { + if (!canApply(recipe)) { return ResolutionResult.pass(); } @@ -46,7 +45,7 @@ public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe re } for (SubResolver subResolver : this.subResolvers) { - Configuration result = subResolver.resolve(mixin, context, recipe); + Configuration result = subResolver.resolve(context, recipe); if (result != null) { return ResolutionResult.success(result); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java index 26eabef4..2966dd40 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java @@ -3,7 +3,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; @@ -40,5 +39,5 @@ public Optional maybePatch() { } @NotNull - ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe); + ResolutionResult resolve(MixinContext context, Recipe recipe); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java index eadbfd9e..846e6a64 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java @@ -8,7 +8,13 @@ public class Resolvers extends OrderedRegistry { public Resolvers() { - registerDefaultResolvers(); + this(true); + } + + public Resolvers(boolean registerDefault) { + if (registerDefault) { + registerDefaultResolvers(); + } } private void registerDefaultResolvers() { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java index d52fabda..d65cfb8c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java @@ -2,11 +2,10 @@ import org.jetbrains.annotations.Nullable; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; public interface SubResolver { @Nullable - Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe); + Configuration resolve(MixinContext context, Recipe recipe); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java index 8f9ad742..26a97b06 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java @@ -5,7 +5,6 @@ import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; @@ -13,8 +12,8 @@ import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -28,10 +27,10 @@ public class ArbitraryInjectionPointSubResolver implements SubResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + public Configuration resolve(MixinContext context, Recipe recipe) { String injectionPointTarget = recipe.clean().getAtData().getTarget().orElseThrow(); - MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); - MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + TargetPair cleanTarget = recipe.getCleanTarget(); + TargetPair dirtyTarget = recipe.getDirtyTarget(); AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanTarget); if (cleanInsn == null) { return null; @@ -41,7 +40,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Recipe recip if (targetMethodCall == null) return null; if (targetMethodCall.owner.equals(dirtyTarget.classNode().name)) { - MethodContext.TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), MethodQualifier.create(targetMethodCall)); + TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), MethodQualifier.create(targetMethodCall)); if (target == null) return null; // New method is in the same class? It's possible our target injection point was moved there @@ -50,7 +49,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Recipe recip } } - return MutableConfiguration.create().setAtData(new AtData(AT_VAL_INVOKE, targetMethodCall)); + return MutableConfiguration.create().setAtData(AtData.create(AT_VAL_INVOKE, targetMethodCall)); } private MethodInsnNode resolveTargetCallInsn(MethodNode dirtyTargetMethod, AbstractInsnNode cleanInjectionInsn, MixinContext context, String injectionPointTarget) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java index c802937e..3335a73c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java @@ -3,13 +3,12 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -24,14 +23,14 @@ public class AtVariableAssignStoreSubResolver implements SubResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + public Configuration resolve(MixinContext context, Recipe recipe) { if (!recipe.clean().getAtData().getValue().equals(AT_VAL_INVOKE)) return null; - MethodContext.TargetPair cleanPair = recipe.getCleanTarget(); + TargetPair cleanPair = recipe.getCleanTarget(); AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanPair); if (cleanInsn == null) return null; - MethodContext.TargetPair dirtyPair = recipe.getDirtyTarget(); + TargetPair dirtyPair = recipe.getDirtyTarget(); if (dirtyPair == null) return null; // Check that the following instruction is a store operation diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java index 52e239d4..a6e90f13 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java @@ -8,14 +8,14 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ConstantData; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup; import org.sinytra.adapter.next.env.param.Parameter; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.SpecialKeys; import org.sinytra.adapter.next.pipeline.processor.wrapop.WrapOpSurgeon; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; import org.sinytra.adapter.patch.analysis.MethodLabelComparator; @@ -23,6 +23,7 @@ import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.Collection; @@ -36,10 +37,10 @@ public abstract class ComparingInjectionPointResolver implements SubResolver { @Nullable protected AbstractInsnNode prepare(MixinContext context, Recipe recipe) { - MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + TargetPair dirtyTarget = recipe.getDirtyTarget(); if (dirtyTarget == null) return null; - MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + TargetPair cleanTarget = recipe.getCleanTarget(); if (cleanTarget == null) return null; return context.methods().findInjectionTargetInsn(cleanTarget); @@ -48,8 +49,8 @@ protected AbstractInsnNode prepare(MixinContext context, Recipe recipe) { public static class Inject extends ComparingInjectionPointResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { - MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); + public Configuration resolve(MixinContext context, Recipe recipe) { + TargetPair cleanTarget = recipe.getCleanTarget(); if (cleanTarget == null) return null; AbstractInsnNode cleanInsn = prepare(context, recipe); @@ -75,7 +76,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Recipe recip for (AbstractInsnNode insn : insns) { if (insn instanceof MethodInsnNode minsn) { return MutableConfiguration.create() - .setAtData(new AtData(AT_VAL_INVOKE, minsn)); + .setAtData(AtData.create(AT_VAL_INVOKE, minsn)); } } } @@ -85,7 +86,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Recipe recip private static Configuration attemptExtractMixin(MethodInsnNode minsn, MixinContext context, Configuration clean) { // Looks like some code was moved into a static method outside this class // Attempt extracting mixin - MethodContext.TargetPair target = context.methods().findMethodPair(context.dirtyLookup(), MethodQualifier.create(minsn)); + TargetPair target = context.methods().findMethodPair(context.dirtyLookup(), MethodQualifier.create(minsn)); if (target == null) return null; // MethodUpgrader.adjustInjectorOrdinalForNewMethod(minsn, context.legacy()); FIXME @@ -96,15 +97,15 @@ private static Configuration attemptExtractMixin(MethodInsnNode minsn, MixinCont .setTargetClass(target.classNode().name) .setTargetMethod(minsn) .setAtData(clean.getAtData().withOrdinal(null)) // TODO Find new ordinal - .setProperty(Configuration.SpecialKeys.EXTRACT_TARGET, minsn); + .setProperty(SpecialKeys.EXTRACT_TARGET, minsn); } } public static class WrapOperation extends ComparingInjectionPointResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { - MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + public Configuration resolve(MixinContext context, Recipe recipe) { + TargetPair dirtyTarget = recipe.getDirtyTarget(); if (dirtyTarget == null) return null; AbstractInsnNode cleanInsn = prepare(context, recipe); @@ -144,7 +145,7 @@ private static Optional handleWrapOperationToInstanceOf(Recipe re List inheritedParams = clean.getParameters().getTypes(ParamGroup.METHOD_PARAMS); Multimap usedVars = WrapOpSurgeon.getUsedVars(mixinLocals, inheritedParams, context); - MutableConfiguration config = recipe.dirty().subConfig() + MutableConfiguration config = recipe.dirty().copyClean() .removeProperty(Keys.TARGET_AT) .setProperty(Keys.TARGET_CONSTANT, ConstantData.classValue(Type.getObjectType(instanceOfCall.desc))) .inheritParameters() @@ -203,7 +204,7 @@ private static Optional handleWrapOperationAdaptedTarget(List handleWrapOperationNewInjectionPoint(MethodInsnNode cleanInjectionInsn, List cleanLabel, List> hunkLabels) { @@ -229,21 +230,21 @@ private static Optional handleWrapOperationNewInjectionPoint(Meth MethodInsnNode dirtyMinsn = methodCalls.getFirst(); return Optional.of(MutableConfiguration.create() - .setAtData(new AtData(AT_VAL_INVOKE, dirtyMinsn))); + .setAtData(AtData.create(AT_VAL_INVOKE, dirtyMinsn))); } - private static Optional handleTargetModification(List> hunkLabels, MethodContext.TargetPair dirtyTarget, MixinContext context) { + private static Optional handleTargetModification(List> hunkLabels, TargetPair dirtyTarget, MixinContext context) { ClassNode dirtyClass = dirtyTarget.classNode(); return hunkLabels.stream() .flatMap(Collection::stream) .filter(insn -> insn instanceof MethodInsnNode minsn && minsn.owner.equals(dirtyClass.name)) .map(MethodInsnNode.class::cast) .filter(minsn -> { - MethodContext.TargetPair pair = context.methods().findMethodPair(context.dirtyLookup(), MethodQualifier.create(minsn)); + TargetPair pair = context.methods().findMethodPair(context.dirtyLookup(), MethodQualifier.create(minsn)); return pair != null && context.methods().hasInjectionTargetInsns(pair); }) .map(minsn -> MutableConfiguration.create() - .setAtData(new AtData(AT_VAL_INVOKE, minsn))) + .setAtData(AtData.create(AT_VAL_INVOKE, minsn))) .findFirst(); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java new file mode 100644 index 00000000..723aa8fd --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java @@ -0,0 +1,85 @@ +package org.sinytra.adapter.next.pipeline.resolver.injection; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup; +import org.sinytra.adapter.next.env.param.Parameter; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.resolver.SubResolver; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; +import org.sinytra.adapter.patch.util.MethodQualifier; + +import java.util.List; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; + +// TODO Test +public class InheritedInjectionPointSubResolver implements SubResolver { + @Nullable + @Override + public Configuration resolve(MixinContext context, Recipe recipe) { + if (!recipe.hasInjectionPointValue(AT_VAL_INVOKE)) return null; + + AtData at = recipe.clean().getAtData(); + MethodQualifier atTarget = at.getTarget().flatMap(MethodQualifier::create).orElseThrow(); + if (atTarget == null) return null; + + TargetPair targetPair = recipe.getDirtyTarget(); + if (targetPair == null) return null; + + List insns = context.methods().findInjectionTargetInsns(targetPair); + if (!insns.isEmpty()) return null; + + String owner = atTarget.internalOwnerName(); + for (AbstractInsnNode insn : targetPair.methodNode().instructions) { + if (insn instanceof MethodInsnNode minsn + && minsn.name.equals(atTarget.name()) && minsn.desc.equals(atTarget.desc()) && !minsn.owner.equals(owner) + && (context.environment().inheritanceHandler().isClassInherited(minsn.owner, owner) || isFixedField(minsn, context.patchContext())) + ) { + MutableConfiguration config = MutableConfiguration.create(); + config.setAtData(at.withTarget(minsn)); + + if (context.methodAnnotation().matchesDesc(MixinConstants.REDIRECT) && minsn.getOpcode() != Opcodes.INVOKESTATIC) { + MethodParameters params = recipe.clean().getParameters().copy(); + List callParams = params.get(ParamGroup.METHOD_PARAMS); + if (!callParams.isEmpty()) { + Parameter first = callParams.getFirst().extend() + .annotate(MixinConstants.COERCE, b -> b.visible(false)) + .build(); + callParams.set(0, first); + config.setParameters(params); + } + } + + return config; + } + } + + return null; + } + + private boolean isFixedField(AbstractInsnNode insn, PatchContext context) { + for (AbstractInsnNode prev = insn.getPrevious(); prev != null; prev = prev.getPrevious()) { + if (prev instanceof LabelNode) { + break; + } + if (prev instanceof FieldInsnNode finsn) { + BytecodeFixerUpper bfu = context.environment().bytecodeFixerUpper(); + return bfu.getFieldTypeChange(finsn.owner, finsn.name) != null; + } + } + return false; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java index ccaa478b..bde6baae 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java @@ -3,35 +3,35 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AbstractInsnNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.TargetPair; import java.util.List; public class InjectionPointResolver extends CompoundResolver { public InjectionPointResolver() { + addSubResolver(new InheritedInjectionPointSubResolver()); addSubResolver(InjectionPointSubResolvers.REPLACED_TYPE); } @Override - protected boolean canApply(MixinData mixin, Recipe recipe) { + protected boolean canApply(Recipe recipe) { return recipe.dirty().getAtData() == null; } @Nullable @Override protected Configuration tryReuse(MixinContext context, Recipe recipe) { - MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + TargetPair dirtyTarget = recipe.getDirtyTarget(); if (dirtyTarget == null) return null; // Try reusing the original List insns = context.methods().findInjectionTargetInsns(dirtyTarget); if (!insns.isEmpty()) { - return recipe.dirty().subConfig() + return recipe.dirty().copyClean() .inheritAtData(); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java index d3389a32..f4b4a979 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java @@ -8,7 +8,6 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.WeighedDisambiguation; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; @@ -16,7 +15,7 @@ import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; @@ -26,11 +25,11 @@ import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; public class InjectionPointSubResolvers { - public static final SubResolver REPLACED_TYPE = (MixinData mixin, MixinContext context, Recipe recipe) -> { + public static final SubResolver REPLACED_TYPE = (MixinContext context, Recipe recipe) -> { if (!recipe.clean().getAtData().getValue().equals(AT_VAL_INVOKE)) return null; - MethodContext.TargetPair cleanPair = recipe.getCleanTarget(); - MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + TargetPair cleanPair = recipe.getCleanTarget(); + TargetPair dirtyTarget = recipe.getDirtyTarget(); // Find single clean target minsn List insns = context.methods().findInjectionTargetInsns(cleanPair); if (insns.isEmpty() || !(insns.getFirst() instanceof MethodInsnNode cleanInsn)) return null; @@ -75,7 +74,7 @@ private static List testMatchers(MixinContext context, MethodIn .toList(); } - private static List testOverloadedMethods(MixinContext context, MethodInsnNode cleanInsn, MethodContext.TargetPair cleanPair, MethodContext.TargetPair dirtyPair) { + private static List testOverloadedMethods(MixinContext context, MethodInsnNode cleanInsn, TargetPair cleanPair, TargetPair dirtyPair) { ClassNode dirtyClass = context.dirtyLookup().getClass(cleanInsn.owner).orElse(null); if (dirtyClass == null) { return List.of(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java index 0f70f7cc..cd139b6b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java @@ -6,36 +6,35 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.TargetPair; import java.util.List; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_STORE; -import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.ORDINAL; +import static org.sinytra.adapter.next.pipeline.config.Keys.ORDINAL; public class ModifyVarInjectionPointSubResolver implements SubResolver { @Nullable @Override - public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { + public Configuration resolve(MixinContext context, Recipe recipe) { if (!recipe.clean().getAtData().getValue().equals(AT_VAL_STORE)) return null; - MethodContext.TargetPair dirtyPair = recipe.getDirtyTarget(); + TargetPair dirtyPair = recipe.getDirtyTarget(); if (dirtyPair == null) return null; - + // Find replacement - Integer ordinal = mixin.getProperty(ORDINAL).orElse(null); + Integer ordinal = recipe.clean().getProperty(ORDINAL).orElse(null); if (ordinal == null) return null; Type varType = Type.getReturnType(context.methodNode().desc); - MethodContext.TargetPair cleanPair = recipe.getCleanTarget(); + TargetPair cleanPair = recipe.getCleanTarget(); LocalVariableLookup lookup = new LocalVariableLookup(cleanPair.methodNode()); LocalVariableNode desired = lookup.getByTypedOrdinal(varType, ordinal).orElseThrow(); @@ -55,7 +54,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Recipe recip if (lvs.size() == 1) { int dirtyOrdinal = dirtyLookup.getOrdinal(lvs.getFirst()); - return recipe.dirty().subConfig() + return recipe.dirty().copyClean() .setProperty(ORDINAL, dirtyOrdinal) .setTargetMethod(method) .inheritAtData(); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java similarity index 70% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java rename to definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java index d3649bc3..38fd2c7c 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicInjectorOrdinalPatch.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.dynamic; +package org.sinytra.adapter.next.pipeline.resolver.special; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; @@ -6,92 +6,116 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.resolver.Resolver; +import org.sinytra.adapter.patch.analysis.InsnComparator; +import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -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.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.GeneratedVariables; import org.sinytra.adapter.patch.util.SingleValueHandle; import java.util.*; -import java.util.function.Consumer; +import java.util.function.Function; -public class DynamicInjectorOrdinalPatch implements MethodTransform { +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_RETURN; + +public class InjectorOrdinalResolver implements Resolver { private static final Map OFFSET_HANDLERS = Map.of( - "INVOKE", InvokeOffsetHandler.INSTANCE, - "RETURN", ReturnOffsetHandler.INSTANCE + AT_VAL_INVOKE, InvokeOffsetHandler.INSTANCE, + AT_VAL_RETURN, ReturnOffsetHandler.INSTANCE ); @Override - public Collection getAcceptedAnnotations() { - return Set.of(MixinConstants.INJECT, MixinConstants.MODIFY_VAR, MixinConstants.MODIFY_RETURN_VAL); - } + public ResolutionResult resolve(MixinContext context, Recipe recipe) { + Type returnType = recipe.clean().getReturnType(); + if (returnType == null) return ResolutionResult.pass(); - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - Type returnType = Type.getReturnType(methodNode.desc); - List> offsetHandlers = getOffsetHandlers(methodContext, returnType); - if (offsetHandlers.isEmpty()) { - return Patch.Result.PASS; - } - MethodContext.TargetPair cleanTarget = methodContext.findCleanInjectionTarget(); - if (cleanTarget == null) { - return Patch.Result.PASS; - } - MethodContext.TargetPair dirtyTarget = methodContext.findDirtyInjectionTarget(); - if (dirtyTarget == null) { - return Patch.Result.PASS; - } + List> offsetHandlers = getOffsetHandlers(context, recipe.clean(), returnType); + if (offsetHandlers.isEmpty()) return ResolutionResult.pass(); + + TargetPair cleanTarget = recipe.getCleanTarget(); + if (cleanTarget == null) return ResolutionResult.pass(); + + TargetPair dirtyTarget = recipe.getDirtyTarget(); + if (dirtyTarget == null) return ResolutionResult.pass(); boolean applied = false; + MutableConfiguration merged = MutableConfiguration.create(); for (HandlerInstance instance : offsetHandlers) { - applied |= instance.apply(this, methodContext, classNode, methodNode, cleanTarget, dirtyTarget); + Configuration config = instance.apply(context, cleanTarget, dirtyTarget); + if (config != null) { + applied = true; + merged.mergeFrom(config); + } } - return applied ? Patch.Result.APPLY : Patch.Result.PASS; + + return applied ? ResolutionResult.success(merged) : ResolutionResult.pass(); } - private static List> getOffsetHandlers(MethodContext methodContext, Type returnType) { + private static List> getOffsetHandlers(MixinContext context, Configuration cleanConfig, Type returnType) { + AtData at = cleanConfig.getAtData(); List> handlers = new ArrayList<>(); - AnnotationHandle annotation = methodContext.injectionPointAnnotationOrThrow(); - - annotation.getValue("ordinal").ifPresent(atOrdinal -> { - String target = annotation.getValue("target").map(AnnotationValueHandle::get).orElse(null); - annotation.getValue("value") - .map(AnnotationValueHandle::get) - .map(OFFSET_HANDLERS::get) - .filter(handler -> !handler.requiresTarget() || target != null) - .ifPresent(h -> handlers.add(new HandlerInstance<>(h, new OffsetUpdateHandler.Context(target, atOrdinal.get()), atOrdinal::set))); + + at.getProperty(AtData.Keys.ORDINAL).ifPresent(ordinal -> { + String target = at.getTarget().orElse(null); + OffsetUpdateHandler handler = OFFSET_HANDLERS.get(at.getValue()); + if (handler != null && (!handler.requiresTarget() || target != null)) { + OffsetUpdateHandler.Context handleContext = new OffsetUpdateHandler.Context(target, ordinal); + HandlerInstance instance = new HandlerInstance<>(handler, handleContext, i -> + MutableConfiguration.create() + .setAtData(at.withOrdinal(i)) + ); + handlers.add(instance); + } }); - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.MODIFY_VAR)) { - LocalVariableLookup cleanTable = methodContext.cleanLocalsTable(); + + if (context.methodAnnotation().matchesDesc(MixinConstants.MODIFY_VAR)) { + LocalVariableLookup cleanTable = context.legacy().cleanLocalsTable(); if (cleanTable != null) { // Handle modified ordinals - methodContext.methodAnnotation().getValue("ordinal") - .flatMap(ordinal -> cleanTable.getByTypedOrdinal(returnType, ordinal.get()) + cleanConfig.getProperty(Keys.ORDINAL) + .flatMap(ordinal -> cleanTable.getByTypedOrdinal(returnType, ordinal) .flatMap(lvn -> cleanTable.getTypedOrdinal(lvn).map(o -> new LocalVar(lvn, o, true))) - .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, var -> ordinal.set(var.ordinal())))) + .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, var -> + MutableConfiguration.create() + .setProperty(Keys.ORDINAL, var.ordinal()) + ))) // Handle modified indexes - .or(() -> methodContext.methodAnnotation().getValue("index") - .flatMap(index -> Optional.ofNullable(cleanTable.getByIndexOrNull(index.get())) + .or(() -> cleanConfig.getProperty(Keys.INDEX) + .flatMap(i -> Optional.ofNullable(cleanTable.getByIndexOrNull(i)) .flatMap(lvn -> cleanTable.getTypedOrdinal(lvn).map(o -> new LocalVar(lvn, o, false))) - .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, var -> index.set(var.lvn().index))))) + .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, var -> + MutableConfiguration.create() + .setProperty(Keys.INDEX, var.lvn().index) + )) + )) .ifPresent(handlers::add); } } + return handlers; } private interface UpdateHandler { - Optional apply(MethodContext methodContext, ClassNode classNode, MethodNode methodNode, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget, T context); + Optional apply(MixinContext mixinContext, TargetPair cleanTarget, TargetPair dirtyTarget, T context); } private interface OffsetUpdateHandler extends UpdateHandler { - record Context(@Nullable String target, int ordinal) {} + record Context(@Nullable String target, int ordinal) { + } default boolean requiresTarget() { return false; @@ -104,16 +128,16 @@ public LocalVar(LocalVariableNode lvn, int ordinal) { } } - private record HandlerInstance(UpdateHandler handler, T context, Consumer applicator) { - public boolean apply(MethodTransform transform, MethodContext methodContext, ClassNode classNode, MethodNode methodNode, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget) { - Optional updatedValue = this.handler.apply(methodContext, classNode, methodNode, cleanTarget, dirtyTarget, this.context); + private record HandlerInstance(UpdateHandler handler, T context, Function applicator) { + @Nullable + public Configuration apply(MixinContext mixinContext, TargetPair cleanTarget, TargetPair dirtyTarget) { + Optional updatedValue = this.handler.apply(mixinContext, cleanTarget, dirtyTarget, this.context); if (updatedValue.isPresent()) { U value = updatedValue.get(); - methodContext.recordAudit(transform, "Update injection point ordinal from %s to %s", this.context, value); - this.applicator.accept(value); - return true; +// methodContext.recordAudit(transform, "Update injection point ordinal from %s to %s", this.context, value); + return this.applicator.apply(value); } - return false; + return null; } } @@ -126,23 +150,22 @@ public boolean requiresTarget() { } @Override - public Optional apply(MethodContext methodContext, ClassNode classNode, MethodNode methodNode, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget, Context context) { + public Optional apply(MixinContext mixinContext, TargetPair cleanTarget, TargetPair dirtyTarget, Context context) { String target = context.target(); int ordinal = context.ordinal(); Multimap cleanCallsMap = MethodAnalyzer.getMethodCalls(cleanTarget.methodNode(), new ArrayList<>()); Multimap dirtyCallsMap = MethodAnalyzer.getMethodCalls(dirtyTarget.methodNode(), new ArrayList<>()); - PatchContext patchContext = methodContext.patchContext(); + PatchContext patchContext = mixinContext.patchContext(); String cleanValue = patchContext.remap(target); Collection cleanCalls = cleanCallsMap.get(cleanValue); String dirtyValue = patchContext.remap(target); Collection dirtyCalls = dirtyCallsMap.get(dirtyValue); if (cleanCalls.size() != dirtyCalls.size()) { - int insnRange = 5; - List cleanMatchers = cleanCalls.stream().map(i -> MethodInsnMatcher.findSurroundingInstructions(i, insnRange)).toList(); - List dirtyMatchers = dirtyCalls.stream().map(i -> MethodInsnMatcher.findSurroundingInstructions(i, insnRange)).toList(); + List cleanMatchers = cleanCalls.stream().map(MethodInsnMatcher::findSurroundingInstructions).toList(); + List dirtyMatchers = dirtyCalls.stream().map(MethodInsnMatcher::findSurroundingInstructions).toList(); if (ordinal >= 0 && ordinal < cleanMatchers.size()) { InstructionMatcher original = cleanMatchers.get(ordinal); @@ -164,7 +187,7 @@ private static class ReturnOffsetHandler implements OffsetUpdateHandler { private static final Set RETURN_OPCODES = Set.of(Opcodes.RETURN, Opcodes.ARETURN, Opcodes.IRETURN, Opcodes.FRETURN, Opcodes.DRETURN, Opcodes.LRETURN); @Override - public Optional apply(MethodContext methodContext, ClassNode classNode, MethodNode methodNode, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget, Context context) { + public Optional apply(MixinContext mixinContext, TargetPair cleanTarget, TargetPair dirtyTarget, Context context) { int ordinal = context.ordinal(); List cleanReturnInsns = findReturnInsns(cleanTarget.methodNode()); @@ -183,6 +206,7 @@ public Optional apply(MethodContext methodContext, ClassNode classNode, return Optional.of(dirtyMatchers.indexOf(matches.getFirst())); } } + return Optional.empty(); } @@ -219,21 +243,26 @@ private static class ModifyVariableOffsetHandler implements UpdateHandler apply(MethodContext methodContext, ClassNode classNode, MethodNode methodNode, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget, LocalVar local) { + public Optional apply(MixinContext mixinContext, TargetPair cleanTarget, TargetPair dirtyTarget, LocalVar local) { + MethodNode methodNode = mixinContext.methodNode(); + Type[] args = Type.getArgumentTypes(methodNode.desc); if (args.length < 1) { return Optional.empty(); } + Type targetType = args[0]; // Gradually expand supported types over time as necessary if (targetType != Type.BOOLEAN_TYPE && targetType != Type.INT_TYPE && targetType != Type.FLOAT_TYPE) { return Optional.empty(); } - if (methodContext.methodAnnotation().getValue("slice").isPresent() && local.relative()) { + + if (mixinContext.methodAnnotation().getValue("slice").isPresent() && local.relative()) { return Optional.empty(); } + return tryFindUpdatedIndex(targetType, cleanTarget, dirtyTarget, local) - .or(() -> tryFindSyntheticVariableIndex(methodContext, methodNode, cleanTarget, dirtyTarget, local)); + .or(() -> tryFindSyntheticVariableIndex(mixinContext, methodNode, cleanTarget, dirtyTarget, local)); } /** @@ -264,7 +293,7 @@ public Optional apply(MethodContext methodContext, ClassNode classNode * INVOKEVIRTUAL net/minecraft/world/entity/player/Player.setHealth (F)V * } */ - private static Optional tryFindSyntheticVariableIndex(MethodContext methodContext, MethodNode methodNode, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget, LocalVar local) { + private static Optional tryFindSyntheticVariableIndex(MixinContext mixinContext, MethodNode methodNode, TargetPair cleanTarget, TargetPair dirtyTarget, LocalVar local) { int ordinal = local.ordinal(); Type variableType = Type.getReturnType(methodNode.desc); LocalVariableLookup cleanTable = new LocalVariableLookup(cleanTarget.methodNode()); @@ -273,10 +302,10 @@ private static Optional tryFindSyntheticVariableIndex(MethodContext me List available = dirtyTable.getForType(variableType); if (available.size() > ordinal) { int variableIndex = available.get(ordinal).index; - List cleanInsns = methodContext.findInjectionTargetInsns(cleanTarget); - List dirtyInsns = methodContext.findInjectionTargetInsns(dirtyTarget); - if (cleanInsns.size() == 1 && dirtyInsns.size() == 1) { - for (AbstractInsnNode insn = cleanInsns.getFirst(); insn != null; insn = insn.getNext()) { + AbstractInsnNode cleanInsn = mixinContext.methods().findInjectionTargetInsn(cleanTarget); + AbstractInsnNode dirtyInsn = mixinContext.methods().findInjectionTargetInsn(dirtyTarget); + if (cleanInsn != null && dirtyInsn != null) { + for (AbstractInsnNode insn = cleanInsn; insn != null; insn = insn.getNext()) { if (insn instanceof LabelNode) { break; } @@ -284,12 +313,14 @@ private static Optional tryFindSyntheticVariableIndex(MethodContext me if (handle != null && handle.get() == variableIndex) { // We found out the variable is used right after our injection point // Now let's check if it its index remain the same in the dirty target - List> dirtyVars = getUsedVariablesInLabel(dirtyInsns.getFirst(), insn.getOpcode()); + List> dirtyVars = getUsedVariablesInLabel(dirtyInsn, insn.getOpcode()); if (dirtyVars.size() == 1) { int dirtyIndex = dirtyVars.getFirst().get(); if (dirtyIndex != variableIndex) { - methodContext.methodAnnotation().getValue("argsOnly") + // FIXME Cannot use set + mixinContext.methodAnnotation().getValue("argsOnly") .ifPresent(h -> h.set(false)); + // Find new ordinal by index LocalVariableNode lvn = dirtyTable.getByIndex(dirtyIndex); return dirtyTable.getTypedOrdinal(lvn) @@ -321,7 +352,7 @@ private static List> getUsedVariablesInLabel(Abstract return list; } - private static Optional tryFindUpdatedIndex(Type targetType, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget, LocalVar local) { + private static Optional tryFindUpdatedIndex(Type targetType, TargetPair cleanTarget, TargetPair dirtyTarget, LocalVar local) { int ordinal = local.ordinal(); List cleanLocals = cleanTarget.methodNode().localVariables.stream() .filter(l -> Type.getType(l.desc) == targetType) diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java new file mode 100644 index 00000000..d42428ca --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java @@ -0,0 +1,147 @@ +package org.sinytra.adapter.next.pipeline.resolver.special; + +import com.mojang.datafixers.util.Pair; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; +import org.sinytra.adapter.next.pipeline.resolver.Resolver; +import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.patch.util.MockMixinRuntime; +import org.spongepowered.asm.mixin.injection.modify.LocalVariableDiscriminator; +import org.spongepowered.asm.mixin.injection.struct.InjectionInfo; +import org.spongepowered.asm.mixin.injection.struct.Target; + +import java.util.List; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_RETURN; + +/** + * Original mixin: + * + *
{@code @ModifyVariable(
+ *     method = "exampleMethod",
+ *     at = @At("RETURN")
+ * )
+ * private void someMethodMixin(int original) {
+ *     return original * 2;
+ * }
+ * }
+ *

+ * Original target: + * + *

{@code
+ * public int exampleMethod() {
+ *     int i = 10;
+ *     // ...
+ * <<< return i;
+ * >>> return localvar$zfk000$someMethodMixin(i);
+ * }
+ * }
+ *

+ * Patched target: + *

{@code
+ * public int exampleMethod() {
+ *     int i = 10;
+ *     // ...
+ * <<< return EventHooks.wrapVariable(i);
+ * >>> return EventHooks.wrapVariable(modify$zfk000$someMethodMixin(i));
+ * }
+ * }
+ *

+ * Patched mixin: + * + *

{@code @ModifyArg(
+ *     method = "exampleMethod",
+ *     at = @At(
+ *         value = "INVOKE",
+ *         target="Lcom/example/EventHooks;wrapVariable(I)I"
+ *     ),
+ *     index = 0
+ * )
+ * private void someMethodMixin(int original) {
+ *     return original * 2;
+ * }
+ * }
+ */ +public class ModifyVarAtReturnResolver implements Resolver { + @Override + public ResolutionResult resolve(MixinContext context, Recipe recipe) { + AtData at = recipe.clean().getAtData(); + if (!AT_VAL_RETURN.equals(at.getValue())) return ResolutionResult.pass(); + + // Find injection targets + TargetPair cleanTarget = recipe.getCleanTarget(); + if (cleanTarget == null) return ResolutionResult.pass(); + TargetPair dirtyTarget = recipe.getDirtyTarget(); + if (dirtyTarget == null) return ResolutionResult.pass(); + + int ordinal = at.getOrdinal().orElse(-1); + Pair cleanTargetPair = getTargetPair(recipe.clean(), context, cleanTarget, ordinal); + // In CLEAN, previous insn is VarInsn for the modified variable + if (cleanTargetPair == null || !(cleanTargetPair.getFirst() instanceof VarInsnNode cleanVarInsn) || cleanVarInsn.var != cleanTargetPair.getSecond()) { + return ResolutionResult.pass(); + } + // In DIRTY, previous insn (as in, before the RETURN insn) is a method call + Pair dirtyTargetPair = getTargetPair(recipe.clean(), context, dirtyTarget, ordinal); + // In CLEAN, previous insn is VarInsn for the modified variable + if (dirtyTargetPair == null || !(dirtyTargetPair.getFirst() instanceof MethodInsnNode dirtyMinsn)) { + return ResolutionResult.pass(); + } + // Get method call argument instructions + List args = MethodCallAnalyzer.getMethodCallSrcInsns(dirtyTarget.methodNode(), dirtyMinsn); + if (args == null) { + return ResolutionResult.pass(); + } + + for (int i = 0; i < args.size(); i++) { + AbstractInsnNode insn = args.get(i); + if (insn instanceof VarInsnNode varInsn && varInsn.var == cleanTargetPair.getSecond()) { + Configuration config = recipe.dirty().copyClean() + .setMixinType(MixinConstants.MODIFY_ARG) + .inheritTargetClass() + .inheritTargetMethod() + .setAtData(AtData.create(AT_VAL_INVOKE, dirtyMinsn)) + .inheritParameters() + .inheritReturnType() + .setProperty(Keys.INDEX, i); + + // TODO Audit +// String qualifier = MethodQualifier.create(dirtyMinsn).asDescriptor(); +// context.legacy().recordAudit(this, "Redirect RETURN variable modifier to parameter %s of method call to %s", i, qualifier); + return ResolutionResult.replace(config); + } + } + + return ResolutionResult.pass(); + } + + private static Pair getTargetPair(Configuration clean, MixinContext context, TargetPair injectionTarget, int ordinal) { + // Find injection point insn + List targetInsns = context.methods().findInjectionTargetInsns(injectionTarget); + if (targetInsns.isEmpty()) return null; + + int index = ordinal == -1 ? targetInsns.size() - 1 : ordinal; + if (index >= targetInsns.size()) return null; + + AbstractInsnNode targetInsn = targetInsns.get(index); + // Find modified variable + LocalVariableDiscriminator discriminator = LocalVariableDiscriminator.parse(context.methodAnnotation().unwrap()); + InjectionInfo injectionInfo = MockMixinRuntime.forInjectionInfo(context.classNode().name, injectionTarget.classNode().name, context.environment()); + + Type returnType = clean.getReturnType(); + Target target = MockMixinRuntime.createMixinTarget(injectionTarget); + LocalVariableDiscriminator.Context ctx = new LocalVariableDiscriminator.Context(injectionInfo, returnType, discriminator.isArgsOnly(), target, targetInsn); + + int local = discriminator.findLocal(ctx); + return Pair.of(targetInsn, local); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java new file mode 100644 index 00000000..d9c766b7 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java @@ -0,0 +1,95 @@ +package org.sinytra.adapter.next.pipeline.resolver.special; + +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.resolver.Resolver; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.spongepowered.asm.mixin.injection.At; + +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN; + +/** + * Upgrade a ModifyVar to a ModifyExpressionVal + * Original mixin: + * + *
{@code @ModifyVariable(
+ *     method = "exampleMethod",
+ *     at = @At(
+ *         value = "INVOKE",
+ *         target = "someOtherMethod()I",
+ *         shift = At.Shift.BY,
+ *         by = 2
+ *     )
+ * )
+ * private void someMethodMixin(int original) {
+ *     return original * 2;
+ * }
+ * }
+ *

+ * Original target: + * + *

{@code
+ * public int exampleMethod() {
+ *     int i = someOtherMethod();
+ * >>> i = localvar$zfk000$someMethodMixin(i);
+ *     // ...
+ * }
+ * }
+ *

+ * Patched target: + *

{@code
+ * public int exampleMethod() {
+ * <<< int i = someOtherMethod();
+ * >>> int i = modifyExpressionValue$zfk000$someMethodMixin(someOtherMethod());
+ *     // ...
+ * }
+ * }
+ *

+ * Patched mixin: + * + *

{@code @ModifyExpressionValue(
+ *     method = "exampleMethod",
+ *     at = @At(
+ *         value = "INVOKE",
+ *         target="someOtherMethod()I"
+ *     )
+ * )
+ * private void someMethodMixin(int original) {
+ *     return original * 2;
+ * }
+ * }
+ */ +public class ModifyVarUpgradeResolver implements Resolver { + @Override + public ResolutionResult resolve(MixinContext context, Recipe recipe) { + if (!recipe.hasInjectionPointValue(AT_VAL_INVOKE) && !recipe.hasInjectionPointValue(AT_VAL_INVOKE_ASSIGN)) + return ResolutionResult.pass(); + + // Conditions must be met: + // - The injection target value is INVOKE or INVOKE_ASSIGN + // - The target is shifted BY 2 + AtData at = recipe.clean().getAtData(); + if (at == null || at.getTarget().isEmpty()) return ResolutionResult.pass(); + + At.Shift shift = at.getProperty(AtData.Keys.SHIFT).orElse(null); + if (shift != At.Shift.BY) return ResolutionResult.pass(); + + boolean byTwo = at.getProperty(AtData.Keys.BY).map(i -> i == 2).orElse(false); + if (!byTwo) return ResolutionResult.pass(); + + String target = at.getTargetOrThrow(); + Configuration config = recipe.dirty().copyClean() + .setMixinType(MixinConstants.MODIFY_EXPR_VAL) + .inheritTargetClass() + .inheritTargetMethod() + .setAtData(AtData.create(AT_VAL_INVOKE, target)) + .inheritParameters() + .inheritReturnType(); + + // Modify mixin type + return ResolutionResult.replace(config); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java index fcd303e2..28a641cb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java @@ -5,15 +5,14 @@ import org.sinytra.adapter.next.env.Configurations; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.Resolver; import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.TargetPair; import java.util.ArrayList; import java.util.List; @@ -34,12 +33,12 @@ public record ResolverSyntheticInstanceof(boolean skipInsnComparison) implements Resolver { @Override - public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe) { - if (!context.legacy().hasInjectionPointValue(AT_VAL_INVOKE)) + public ResolutionResult resolve(MixinContext context, Recipe recipe) { + if (!recipe.hasInjectionPointValue(AT_VAL_INVOKE)) return ResolutionResult.pass(); - MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); - MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + TargetPair cleanTarget = recipe.getCleanTarget(); + TargetPair dirtyTarget = recipe.getDirtyTarget(); AbstractInsnNode targetInsn = context.methods().findInjectionTargetInsn(cleanTarget); if (targetInsn == null) return ResolutionResult.pass(); @@ -65,11 +64,14 @@ public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe re } int ordinal = getInstanceofOrdinal(dirtyInsns, instanceOfInsn); - Configuration config = recipe.dirty().subConfig() + Configuration config = recipe.dirty().copyClean() .setMixinType(MixinConstants.MODIFY_INSTANCEOF_VAL) .inheritTargetClass() .inheritTargetMethod() - .setAtData(new AtData(AT_VAL_SINYTRA_INSTANCEOF, instanceOfInsn.desc, ordinal != 0 ? ordinal : null)) + .setAtData(AtData.builder(AT_VAL_SINYTRA_INSTANCEOF) + .target(instanceOfInsn.desc) + .ordinal(ordinal != 0 ? ordinal : null) + .build()) .inheritParameters() .inheritReturnType(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java index 72533fb1..383b8917 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java @@ -7,13 +7,12 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.ann.SliceData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.MockMixinRuntime; import org.spongepowered.asm.mixin.injection.code.ISliceContext; @@ -26,12 +25,12 @@ import java.util.Optional; import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.SLICE; +import static org.sinytra.adapter.next.pipeline.config.Keys.SLICE; public class SliceBoundaryResolver implements Resolver { @Override - public ResolutionResult resolve(MixinData mixin, MixinContext context, Recipe recipe) { - MethodContext.TargetPair dirtyTarget = recipe.getDirtyTarget(); + public ResolutionResult resolve(MixinContext context, Recipe recipe) { + TargetPair dirtyTarget = recipe.getDirtyTarget(); SliceData slice = recipe.clean().getProperty(SLICE).orElse(null); if (slice == null || passesSliceCheck(slice, context, dirtyTarget)) @@ -86,7 +85,7 @@ private static Optional fixSlideInjectionPoint(AtData boundary, MethodNo return Optional.of(boundary.withTarget(insn)); } - private static boolean passesSliceCheck(SliceData slice, MixinContext context, MethodContext.TargetPair dirtyTarget) { + private static boolean passesSliceCheck(SliceData slice, MixinContext context, TargetPair dirtyTarget) { Target mixinTarget = MockMixinRuntime.createMixinTarget(dirtyTarget); IMixinContext mixinContext = MockMixinRuntime.forClass(context.classNode().name, dirtyTarget.classNode().name, context.patchContext().environment()); ISliceContext sliceContext = MockMixinRuntime.forSlice(mixinContext, context.methodNode()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java index 26d46844..54b89594 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java @@ -10,9 +10,9 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.api.MethodContext; import org.sinytra.adapter.patch.api.MixinClassGenerator; import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -21,8 +21,8 @@ public final class SplitMethodCancellationHelper { public static void handle(Object transform, MixinContext context, Recipe recipe, MethodNode newTarget) { - MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); - MethodContext.TargetPair originalTarget = recipe.getDirtyTarget(); + TargetPair cleanTarget = recipe.getCleanTarget(); + TargetPair originalTarget = recipe.getDirtyTarget(); ClassNode originalClassTarget = originalTarget.classNode(); MethodNode originalMethodTarget = originalTarget.methodNode(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java index ad479b51..4d337b1b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java @@ -6,7 +6,6 @@ import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; @@ -15,10 +14,13 @@ import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; /** * Handle cases where a single method is split into multiple smaller pieces. @@ -26,9 +28,9 @@ */ public class SplitTargetMethodSubResolver implements SubResolver { @Override - public Configuration resolve(MixinData mixin, MixinContext context, Recipe recipe) { - MethodContext.TargetPair cleanTarget = recipe.getCleanTarget(); - MethodContext.TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), recipe.clean().getTargetMethod()); + public Configuration resolve(MixinContext context, Recipe recipe) { + TargetPair cleanTarget = recipe.getCleanTarget(); + TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), recipe.clean().getTargetMethod()); if (cleanTarget == null || dirtyTarget == null) return null; List candidates = disambiguate(locateCandidates(context, cleanTarget, dirtyTarget), context, cleanTarget); @@ -38,7 +40,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Recipe recip // methodContext.recordAudit(this, "Adjusting split method target to %s", newTarget); // TODO Move to processor - if (mixin.isCancellable()) { + if (recipe.clean().isCancellable()) { SplitMethodCancellationHelper.handle(this, context, recipe, method); } @@ -49,7 +51,7 @@ public Configuration resolve(MixinData mixin, MixinContext context, Recipe recip return null; } - private static List locateCandidates(MixinContext context, MethodContext.TargetPair cleanTarget, MethodContext.TargetPair dirtyTarget) { + private static List locateCandidates(MixinContext context, TargetPair cleanTarget, TargetPair dirtyTarget) { MethodNode cleanTargetMethod = cleanTarget.methodNode(); ClassNode dirtyTargetClass = dirtyTarget.classNode(); MethodNode dirtyTargetMethod = dirtyTarget.methodNode(); @@ -65,11 +67,11 @@ private static List locateCandidates(MixinContext context, Meth } List candidates = findInsnsCalls(invocations.stream() - .map(m -> new MethodContext.TargetPair(dirtyTargetClass, m)).toList(), context); + .map(m -> new TargetPair(dirtyTargetClass, m)).toList(), context); // Attempt to find matching insns in lambdas if (candidates.isEmpty()) { - List nestedLambdas = invocations.stream() + List nestedLambdas = invocations.stream() .flatMap(m -> MethodAnalyzer.findLambdasInMethod(dirtyTarget.classNode(), m, null).stream()) .flatMap(s -> MethodQualifier.create(s).stream()) .map(s -> context.methods().findOwnMethodPair(context.dirtyLookup(), s)) @@ -86,7 +88,7 @@ private static List tryFindPartialCandidates(MethodNode cleanTa Multimap cleanMethodCalls = MethodAnalyzer.getMethodCalls(cleanTargetMethod, new ArrayList<>()); Multimap dirtyMethodCalls = MethodAnalyzer.getMethodCalls(dirtyTargetMethod, new ArrayList<>()); - List dirtyOnlyCalls = dirtyMethodCalls.entries().stream() + List dirtyOnlyCalls = dirtyMethodCalls.entries().stream() .filter(e -> !cleanMethodCalls.containsKey(e.getKey()) && e.getValue().owner.equals(dirtyTargetClass.name)) .map(Map.Entry::getValue) .map(i -> context.methods().findOwnMethodPair(context.dirtyLookup(), MethodQualifier.create(i))) @@ -97,7 +99,7 @@ private static List tryFindPartialCandidates(MethodNode cleanTa } // If multiple candidates have been found, try comparing the surrounding method instructions to find one match - private static List disambiguate(List candidates, MixinContext context, MethodContext.TargetPair cleanTarget) { + private static List disambiguate(List candidates, MixinContext context, TargetPair cleanTarget) { if (candidates.size() <= 1) { return candidates; } @@ -124,7 +126,7 @@ private static List disambiguate(List candidat return candidates; } - private static List findInsnsCalls(List methods, MixinContext context) { + private static List findInsnsCalls(List methods, MixinContext context) { return methods.stream() .map(pair -> { List insns = context.methods().findInjectionTargetInsns(pair); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java index 6f70906f..b5e17db1 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java @@ -1,11 +1,10 @@ package org.sinytra.adapter.next.pipeline.resolver.target; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; public class TargetMethodResolver extends CompoundResolver { @@ -16,16 +15,16 @@ public TargetMethodResolver() { } @Override - protected boolean canApply(MixinData mixin, Recipe recipe) { + protected boolean canApply(Recipe recipe) { return recipe.dirty().getTargetMethod() == null; } @Override protected Configuration tryReuse(MixinContext context, Recipe recipe) { MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); - MethodContext.TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); + TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); if (target != null && context.methods().hasInjectionTargetInsns(target)) { - return recipe.dirty().subConfig() + return recipe.dirty().copyClean() .inheritTargetMethod(); } return null; @@ -34,9 +33,9 @@ protected Configuration tryReuse(MixinContext context, Recipe recipe) { @Override protected Configuration useFallback(MixinContext context, Recipe recipe) { MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); - MethodContext.TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); + TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); if (target != null) { - return recipe.dirty().subConfig() + return recipe.dirty().copyClean() .inheritTargetMethod(); } return null; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java index e478cc39..90ab60ef 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java @@ -8,14 +8,13 @@ import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.Resolver; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -33,14 +32,14 @@ public class TargetMethodSubResolvers { *
* DIRTY: Lnet/minecraft/server/level/ServerEntity;sendPairingData(Lnet/minecraft/server/level/ServerPlayer;Lnet/neoforged/neoforge/network/bundle/PacketAndPayloadAcceptor;)V */ - public static final SubResolver CHANGED_METHOD_PARAMS = (MixinData mixin, MixinContext context, Recipe recipe) -> { + public static final SubResolver CHANGED_METHOD_PARAMS = (MixinContext context, Recipe recipe) -> { MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); Pair> candidates = context.methods().findOwnMethodsByName(context.dirtyLookup(), cleanQualifier); if (candidates == null) return null; // Find single matching candidate - Configuration resolved = resolveReplacementCandidate(mixin, context, recipe, candidates.getSecond()); + Configuration resolved = resolveReplacementCandidate(context, recipe, candidates.getSecond()); if (resolved == null) return null; // Only apply single candidate change when the target desc has changed @@ -54,16 +53,16 @@ public class TargetMethodSubResolvers { /** * Handle cases where the target instructions have been moved into a lambda inside the target method */ - public static final SubResolver MOVED_INTO_LAMBDA = (MixinData mixin, MixinContext context, Recipe recipe) -> { + public static final SubResolver MOVED_INTO_LAMBDA = (MixinContext context, Recipe recipe) -> { MethodQualifier cleanQualifier = recipe.clean().getTargetMethod(); - MethodContext.TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); + TargetPair target = context.methods().findOwnMethodPair(context.dirtyLookup(), cleanQualifier); if (target == null) return null; for (AbstractInsnNode insn : target.methodNode().instructions) { // Find lambda invocations and search for target insns inside the lambda if (insn instanceof InvokeDynamicInsnNode indy && indy.bsmArgs.length > 1 && indy.bsmArgs[1] instanceof Handle handle) { - MethodContext.TargetPair lambda = MethodQualifier.create(handle.getName()) + TargetPair lambda = MethodQualifier.create(handle.getName()) .map(q -> context.methods().findOwnMethodPair(context.dirtyLookup(), q)) .orElse(null); if (lambda == null) return null; @@ -79,7 +78,7 @@ public class TargetMethodSubResolvers { }; @Nullable - private static Configuration resolveReplacementCandidate(MixinData mixin, MixinContext context, Recipe recipe, List methods) { + private static Configuration resolveReplacementCandidate(MixinContext context, Recipe recipe, List methods) { if (methods.size() == 1) { return MutableConfiguration.create() .setTargetMethod(methods.getFirst()); @@ -91,10 +90,10 @@ private static Configuration resolveReplacementCandidate(MixinData mixin, MixinC .sorted(Comparator.comparing(m -> m.desc).reversed()) .>flatMap(m -> { Configuration dirtyCopy = recipe.dirty().copy().setTargetMethod(m); - return resolver.resolve(mixin, context, recipe.withDirtyConfig(dirtyCopy)) + return resolver.resolve(context, recipe.withDirtyConfig(dirtyCopy)) .maybePatch() .stream() - .map(c -> Pair.of(m, c.subConfig().setTargetMethod(m))); + .map(c -> Pair.of(m, c.copyClean().setTargetMethod(m))); }) .toList(); if (valid.size() == 1) { @@ -114,7 +113,7 @@ private static Configuration resolveReplacementCandidate(MixinData mixin, MixinC } public static boolean isDirtyDeprecatedMethod(MixinContext context, MethodNode dirty) { - MethodContext.TargetPair pair = context.methods().findOwnMethodPair(context.cleanLookup(), MethodQualifier.create(dirty)); + TargetPair pair = context.methods().findOwnMethodPair(context.cleanLookup(), MethodQualifier.create(dirty)); return (pair == null || !AdapterUtil.hasAnnotation(pair.methodNode().visibleAnnotations, DEPRECATED)) && !AdapterUtil.hasAnnotation(dirty.visibleAnnotations, DEPRECATED); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java new file mode 100644 index 00000000..2f7f1ee4 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java @@ -0,0 +1,10 @@ +package org.sinytra.adapter.next.transform; + +import org.objectweb.asm.tree.ClassNode; +import org.sinytra.adapter.next.env.ann.ClassTarget; +import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.PatchResult; + +public interface ClassTransformer { + PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context); +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypePatchTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/FieldAccessorTypeTransformer.java similarity index 63% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypePatchTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/FieldAccessorTypeTransformer.java index 67b19ef8..fc6d9755 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypePatchTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/FieldAccessorTypeTransformer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.transform; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.AnnotationVisitor; @@ -6,44 +6,48 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.selector.FieldMatcher; -import org.sinytra.adapter.patch.api.*; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.patch.fixes.BytecodeFixerJarGenerator; +import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; +import org.sinytra.adapter.patch.fixes.TypeAdapter; import org.sinytra.adapter.patch.util.AdapterUtil; -import java.util.Collection; -import java.util.Set; - -public class FieldTypePatchTransformer implements MethodTransform { +// TODO Clean up maybe +public class FieldAccessorTypeTransformer implements MethodTransformer { private static final String PREFIX = "adapter$"; + private static final int PRIORITY_MAX = 9999; @Override - public Collection getAcceptedAnnotations() { - return Set.of(MixinConstants.ACCESSOR); - } - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { + public PatchResult apply(MixinContext context, Configuration config) { BytecodeFixerUpper bfu = context.environment().bytecodeFixerUpper(); - if (bfu != null && methodContext.targetTypes().size() == 1) { - String fieldFqn = AdapterUtil.getAccessorTargetFieldName(classNode.name, methodNode, methodContext.methodAnnotation(), context.environment()).orElse(null); - if (fieldFqn != null) { - String fieldName = new FieldMatcher(fieldFqn).getName(); - Type owner = methodContext.targetTypes().getFirst(); - Pair updatedTypes = bfu.getFieldTypeChange(owner.getInternalName(), fieldName); - if (updatedTypes != null) { - TypeAdapter typeAdapter = bfu.getTypeAdapter(updatedTypes.getSecond(), updatedTypes.getFirst()); - if (typeAdapter != null) { - String targetMethod = addRedirectAcceptorField(owner, methodNode, fieldName, typeAdapter, bfu.getGenerator()); + if (bfu == null || context.targetTypes().size() != 1) return PatchResult.PASS; - methodNode.visibleAnnotations.remove(methodContext.methodAnnotation().unwrap()); - AnnotationVisitor invokerAnn = methodNode.visitAnnotation(MixinConstants.INVOKER, true); - invokerAnn.visit("value", targetMethod); - return Patch.Result.APPLY; - } - } + ClassNode classNode = context.classNode(); + MethodNode methodNode = context.methodNode(); + String fieldFqn = AdapterUtil.getAccessorTargetFieldName(classNode.name, methodNode, context.methodAnnotation(), context.environment()) + .orElse(null); + if (fieldFqn == null) return PatchResult.PASS; + + String fieldName = new FieldMatcher(fieldFqn).getName(); + Type owner = context.targetTypes().getFirst(); + Pair updatedTypes = bfu.getFieldTypeChange(owner.getInternalName(), fieldName); + if (updatedTypes != null) { + TypeAdapter typeAdapter = bfu.getTypeAdapter(updatedTypes.getSecond(), updatedTypes.getFirst()); + if (typeAdapter != null) { + String targetMethod = addRedirectAcceptorField(owner, methodNode, fieldName, typeAdapter, bfu.getGenerator()); + + methodNode.visibleAnnotations.remove(context.methodAnnotation().unwrap()); + AnnotationVisitor invokerAnn = methodNode.visitAnnotation(MixinConstants.INVOKER, true); + invokerAnn.visit("value", targetMethod); + return PatchResult.APPLY; } } - return Patch.Result.PASS; + + return PatchResult.PASS; } private String addRedirectAcceptorField(Type owner, MethodNode methodNode, String field, TypeAdapter adapter, BytecodeFixerJarGenerator generator) { @@ -91,7 +95,7 @@ private ClassNode generateFieldAdapterMixin(String className, Type targetClass) valueVisitor.visit(null, targetClass); valueVisitor.visitEnd(); } - mixinAnnotation.visit("priority", 9999); + mixinAnnotation.visit("priority", PRIORITY_MAX); mixinAnnotation.visitEnd(); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java new file mode 100644 index 00000000..8b53ba01 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java @@ -0,0 +1,9 @@ +package org.sinytra.adapter.next.transform; + +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.patch.api.PatchResult; + +public interface MethodTransformer { + PatchResult apply(MixinContext context, Configuration config); +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicAnonClassIndexPatch.java b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java similarity index 67% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicAnonClassIndexPatch.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java index be905679..23ac8d87 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicAnonClassIndexPatch.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java @@ -1,16 +1,16 @@ -package org.sinytra.adapter.patch.transformer.dynamic; +package org.sinytra.adapter.next.transform.cls; -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.InnerClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.PatchInstance; +import org.sinytra.adapter.next.env.ann.ClassTarget; +import org.sinytra.adapter.next.type.MixinTypes; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.api.ClassTransform; -import org.sinytra.adapter.patch.api.Patch; +import org.sinytra.adapter.next.transform.ClassTransformer; import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.api.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -19,33 +19,28 @@ /** * Handle cases where a method targets an anonymous class whose index has changed. */ -public class DynamicAnonClassIndexPatch implements ClassTransform { +public class DynamicAnonClassIndexPatch implements ClassTransformer { @Override - public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle annotation, PatchContext context) { - if (annotation == null || !annotation.getKey().equals("targets")) { - return Patch.Result.PASS; - } - List targets = (List) annotation.get(); - if (targets.size() != 1) { - return Patch.Result.PASS; - } - String theTarget = context.remap(targets.getFirst()); - if (!AdapterUtil.isAnonymousClass(theTarget)) { - return Patch.Result.PASS; + public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context) { + Type singleTarget = classTarget.getSingle(); + String target = singleTarget.getInternalName(); + if (!AdapterUtil.isAnonymousClass(target)) { + return PatchResult.PASS; } - ClassNode cleanClass = context.environment().cleanClassLookup().getClass(theTarget).orElse(null); + ClassNode cleanClass = context.environment().cleanClassLookup().getClass(target).orElse(null); if (cleanClass == null || cleanClass.outerClass == null || cleanClass.outerMethod == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } ClassNode outerDirtyClass = context.environment().dirtyClassLookup().getClass(cleanClass.outerClass).orElse(null); if (outerDirtyClass == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } + // FIXME Cannot use remap here! MethodQualifier cleanOuterMethod = MethodQualifier.create(context.remap(cleanClass.outerMethod + cleanClass.outerMethodDesc)).orElse(null); if (cleanOuterMethod == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } for (InnerClassNode innerClass : outerDirtyClass.innerClasses) { @@ -55,15 +50,15 @@ public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle>getValue("method").ifPresent(val -> { List mapped = val.get().stream() diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicAnonymousShadowFieldTypePatch.java b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java similarity index 64% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicAnonymousShadowFieldTypePatch.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java index c0d79cce..2a59cbd4 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicAnonymousShadowFieldTypePatch.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java @@ -1,39 +1,30 @@ -package org.sinytra.adapter.patch.transformer.dynamic; +package org.sinytra.adapter.next.transform.cls; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.api.ClassTransform; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.next.env.ann.ClassTarget; +import org.sinytra.adapter.next.transform.ClassTransformer; +import org.sinytra.adapter.patch.api.*; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; -public class DynamicAnonymousShadowFieldTypePatch implements ClassTransform { +public class DynamicAnonymousShadowFieldTypePatch implements ClassTransformer { @Override - public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle annotation, PatchContext context) { - if (annotation == null || !annotation.getKey().equals("targets")) { - return Patch.Result.PASS; - } - List targets = (List) annotation.get(); - if (targets.size() != 1) { - return Patch.Result.PASS; + public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context) { + Type singleTarget = classTarget.getSingle(); + String target = singleTarget.getInternalName(); + if (!AdapterUtil.isAnonymousClass(target)) { + return PatchResult.PASS; } - String targetReference = context.remap(targets.getFirst()); - if (!AdapterUtil.isAnonymousClass(targetReference)) { - return Patch.Result.PASS; - } - ClassNode targetClass = context.environment().dirtyClassLookup().getClass(targetReference).orElse(null); + ClassNode targetClass = context.environment().dirtyClassLookup().getClass(target).orElse(null); if (targetClass == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } Map renames = new HashMap<>(); @@ -68,9 +59,9 @@ public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle, Predicate> matchers; + + private ConfigurationMatcher(Map, Predicate> matchers) { + this.matchers = ImmutableMap.copyOf(matchers); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public boolean match(PropertyContainer container) { + for (Map.Entry, Predicate> entry : this.matchers.entrySet()) { + Object value = container.getProperty(entry.getKey()); + if (value == null || !((Predicate) entry.getValue()).test(value)) { + return false; + } + } + return true; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final Map, Predicate> matchers = new HashMap<>(); + + @SuppressWarnings({"rawtypes", "unchecked"}) + public Builder match(PropertyKey prop, Predicate predicate) { + this.matchers.compute(prop, (k, v) -> v == null ? predicate : v.or((Predicate) predicate)); + return this; + } + + public ConfigurationMatcher build() { + return new ConfigurationMatcher(this.matchers); + } + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatch.java b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatch.java new file mode 100644 index 00000000..b6f62825 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatch.java @@ -0,0 +1,18 @@ +package org.sinytra.adapter.next.transform.patch; + +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.transform.MethodTransformer; + +import java.util.List; + +public interface MethodPatch { + ConfigurationMatcher matcher(); + + Configuration configuration(); + + List transforms(); + + static MethodPatchBuilder builder() { + return new MethodPatchBuilderImpl(); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilder.java b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilder.java new file mode 100644 index 00000000..c6e1cfb9 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilder.java @@ -0,0 +1,46 @@ +package org.sinytra.adapter.next.transform.patch; + +import org.objectweb.asm.commons.InstructionAdapter; +import org.sinytra.adapter.next.transform.MethodTransformer; + +import java.util.function.Consumer; + +public interface MethodPatchBuilder { + // Matching + MethodPatchBuilder targetMixinType(String annotationDesc); + + MethodPatchBuilder targetClass(String... targets); + + MethodPatchBuilder targetMethod(String... targets); + + MethodPatchBuilder targetInjectionPoint(String target); + + MethodPatchBuilder targetInjectionPoint(String value, String target); + + MethodPatchBuilder targetConstant(double doubleValue); + + // Interface only + MethodPatchBuilder targetField(String target); + + // Modifications + MethodPatchBuilder extractMixin(String targetClass); + + MethodPatchBuilder modifyTarget(String method); + + MethodPatchBuilder modifyInjectionPoint(String target); + + MethodPatchBuilder modifyInjectionPoint(String value, String target); + + MethodPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues); + + // TODO This should be automatic + MethodPatchBuilder modifyStatic(boolean isStatic); + + MethodPatchBuilder modifyMixinType(String newType); + + MethodPatchBuilder divertRedirector(Consumer patcher); + + MethodPatchBuilder disable(); + + MethodPatchBuilder transform(MethodTransformer transformer); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java new file mode 100644 index 00000000..3c109670 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java @@ -0,0 +1,139 @@ +package org.sinytra.adapter.next.transform.patch; + +import org.objectweb.asm.commons.InstructionAdapter; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.SpecialKeys; +import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.patch.util.MethodQualifier; + +import java.util.ArrayList; +import java.util.List; +import java.util.OptionalDouble; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import static java.util.function.Predicate.isEqual; +import static org.sinytra.adapter.next.pipeline.config.Keys.*; + +public class MethodPatchBuilderImpl implements MethodPatchBuilder { + private final ConfigurationMatcher.Builder matcher = ConfigurationMatcher.builder(); + private final MutableConfiguration config = MutableConfiguration.create(); + private final List transforms = new ArrayList<>(); + + public MethodPatchImpl build() { + ConfigurationMatcher finalMatcher = this.matcher.build(); + return new MethodPatchImpl(finalMatcher, this.config, this.transforms); + } + + @Override + public MethodPatchBuilder targetMixinType(String annotationDesc) { + this.matcher.match(MIXIN_TYPE, isEqual(annotationDesc)); + return this; + } + + @Override + public MethodPatchBuilder targetClass(String... targets) { + Stream.of(targets).forEach(t -> this.matcher.match(TARGET_CLASS, isEqual(t))); + return this; + } + + @Override + public MethodPatchBuilder targetMethod(String... targets) { + Stream.of(targets) + .map(t -> MethodQualifier.create(t).orElseThrow()) + .forEach(t -> this.matcher.match(TARGET_METHOD, q -> q.matches(t))); + return this; + } + + @Override + public MethodPatchBuilder targetInjectionPoint(String target) { + this.matcher.match(TARGET_AT, t -> target.equals(t.getTarget().orElse(null))); + return this; + } + + @Override + public MethodPatchBuilder targetInjectionPoint(String value, String target) { + this.matcher.match(TARGET_AT, t -> value.equals(t.getValue()) && target.equals(t.getTarget().orElse(null))); + return this; + } + + @Override + public MethodPatchBuilder targetConstant(double doubleValue) { + this.matcher.match(TARGET_CONSTANT, c -> { + // TODO OR check at const value + OptionalDouble opt = c.doubleValue(); + return opt.isPresent() && opt.getAsDouble() == doubleValue; + }); + return this; + } + + @Override + public MethodPatchBuilder targetField(String target) { + // TODO + return this; + } + + @Override + public MethodPatchBuilder extractMixin(String targetClass) { + this.config.setTargetClass(targetClass); + return this; + } + + @Override + public MethodPatchBuilder modifyTarget(String method) { + MethodQualifier qualifier = MethodQualifier.create(method).orElseThrow(); + this.config.setTargetMethod(qualifier); + return this; + } + + @Override + public MethodPatchBuilder modifyInjectionPoint(String target) { + // TODO sort out the value placeholder + this.config.setAtData(AtData.create("", target)); + return this; + } + + @Override + public MethodPatchBuilder modifyInjectionPoint(String value, String target) { + // TODO How to not reset other values? + this.config.setAtData(AtData.create(value, target)); + return this; + } + + @Override + public MethodPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues) { + this.config.setAtData(AtData.create(value, target)); + return this; + } + + @Override + public MethodPatchBuilder modifyStatic(boolean isStatic) { + // TODO Attribute + return this; + } + + @Override + public MethodPatchBuilder modifyMixinType(String newType) { + this.config.setMixinType(newType); + return this; + } + + @Override + public MethodPatchBuilder disable() { + this.config.setShouldDelete(true); + return this; + } + + @Override + public MethodPatchBuilder divertRedirector(Consumer patcher) { + this.config.setProperty(SpecialKeys.REDIRECT_ADAPTER, patcher); + return this; + } + + @Override + public MethodPatchBuilder transform(MethodTransformer transformer) { + this.transforms.add(transformer); + return this; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchImpl.java b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchImpl.java new file mode 100644 index 00000000..bfa5a392 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchImpl.java @@ -0,0 +1,33 @@ +package org.sinytra.adapter.next.transform.patch; + +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.transform.MethodTransformer; + +import java.util.List; + +public class MethodPatchImpl implements MethodPatch { + private final ConfigurationMatcher matcher; + private final Configuration config; + private final List transforms; + + public MethodPatchImpl(ConfigurationMatcher matcher, Configuration config, List transforms) { + this.matcher = matcher; + this.config = config; + this.transforms = transforms; + } + + @Override + public ConfigurationMatcher matcher() { + return this.matcher; + } + + @Override + public Configuration configuration() { + return this.config; + } + + @Override + public List transforms() { + return this.transforms; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java new file mode 100644 index 00000000..6d1eec91 --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java @@ -0,0 +1,67 @@ +package org.sinytra.adapter.next.transform.patch; + +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.processor.Processor; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; +import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.patch.api.PatchResult; + +import java.util.ArrayList; +import java.util.List; + +public class MethodPatchTransformer implements MethodTransformer { + private final List patches; + + public MethodPatchTransformer(List patches) { + this.patches = patches; + } + + @Override + public PatchResult apply(MixinContext context, Configuration config) { + Processors processors = new Processors(); + + List postChanges = new ArrayList<>(); + MutableConfiguration dirtyConfig = config.copyClean(); + boolean matched = false; + for (MethodPatch patch : this.patches) { + if (patch.matcher().match(config)) { + matched = true; + + Configuration patchConfig = patch.configuration(); + dirtyConfig.mergeFrom(patchConfig); + postChanges.addAll(patch.transforms()); + } + } + + // Apply changes + if (matched) { + Resolvers resolvers = new Resolvers(false); + Recipe recipe = new Recipe(config, dirtyConfig, resolvers, processors, context); + + processors.freeze(); + for (Processor processor : processors.getAll()) { + TxResult res = processor.process(context, dirtyConfig, recipe); + if (res == TxResult.FINALIZE) { + break; + } + if (res == TxResult.FAIL) { + return PatchResult.PASS; + } + } + + // Apply custom changes + for (MethodTransformer transformer : postChanges) { + transformer.apply(context, config); + } + + return PatchResult.APPLY; + } + + return PatchResult.PASS; + } +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java b/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java similarity index 80% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java index 82197440..4958b4f5 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/dynamic/DynamicLVTPatch.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.dynamic; +package org.sinytra.adapter.next.transform.preprocess; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; @@ -12,6 +12,9 @@ import org.jetbrains.annotations.VisibleForTesting; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.transform.MethodTransformer; import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; @@ -19,7 +22,7 @@ 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.transformer.operation.param.ParamTransformTarget; +import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; import org.spongepowered.asm.mixin.FabricUtil; @@ -30,21 +33,28 @@ import java.util.Set; import java.util.stream.Collectors; -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; +import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; -public class DynamicLVTPatch implements MethodTransform { +// TODO This entire thing should be ditched for the Upgrade transformer using @Local +// And there will be no more rearrangement nonsense +@Deprecated +public class CapturedLocalsPreProcessor implements MethodTransformer { private static final Logger LOGGER = LogUtils.getLogger(); private static final Set ANNOTATIONS = Set.of(MixinConstants.INJECT, MixinConstants.MODIFY_EXPR_VAL, MixinConstants.MODIFY_VAR); @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { + public PatchResult apply(MixinContext context, Configuration config) { + ClassNode classNode = context.classNode(); + MethodNode methodNode = context.methodNode(); + MethodContext methodContext = context.legacy(); + AnnotationHandle annotation = methodContext.methodAnnotation(); if (methodNode.invisibleParameterAnnotations != null) { // Find @Local annotations on method parameters Type[] paramTypes = Type.getArgumentTypes(methodNode.desc); List> localAnnotations = AdapterUtil.getAnnotatedParameters(methodNode, paramTypes, MixinConstants.LOCAL, Pair::of); if (!localAnnotations.isEmpty()) { - Patch.Result result = Patch.Result.PASS; + PatchResult result = PatchResult.PASS; for (Pair pair : localAnnotations) { result = result.or(offsetParameterIndex(new AnnotationHandle(pair.getFirst()), pair.getSecond(), methodContext)); } @@ -52,72 +62,72 @@ public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodCont } } if (!ANNOTATIONS.contains(annotation.getDesc())) { - return Patch.Result.PASS; + return PatchResult.PASS; } if (annotation.matchesDesc(MixinConstants.MODIFY_VAR)) { AnnotationValueHandle ordinal = annotation.getValue("ordinal").orElse(null); if (ordinal == null && annotation.getValue("name").isEmpty()) { Type[] args = Type.getArgumentTypes(methodNode.desc); if (args.length < 1) { - return Patch.Result.PASS; + return PatchResult.PASS; } - MethodContext.TargetPair targetPair = methodContext.findDirtyInjectionTarget(); + TargetPair targetPair = methodContext.findDirtyInjectionTarget(); if (targetPair == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } for (Integer level : methodContext.getLvtCompatLevelsOrdered()) { - List available = methodContext.getTargetMethodLocals(targetPair, 0, level); + List available = methodContext.getTargetMethodLocals(targetPair, 0, level); if (available == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } Type expected = args[0]; int count = (int) available.stream().filter(lv -> lv.type().equals(expected)).count(); if (count == 1) { annotation.appendValue("ordinal", 0); - return Patch.Result.APPLY; + return PatchResult.APPLY; } } } - return Patch.Result.PASS; + return PatchResult.PASS; } // Check if the mixin captures LVT if (annotation.matchesDesc(MixinConstants.INJECT) && annotation.getValue("locals").isPresent()) { ParamsDiffSnapshot diff = compareParameters(classNode, methodNode, methodContext); if (diff != null) { // Apply parameter patch - MethodTransform transform = diff.asParameterTransformer(ParamTransformTarget.METHOD, true); - return transform.apply(methodContext); + TransformParameters transform = diff.asParameterTransformer(true); + return transform.apply(); } } - return Patch.Result.PASS; + return PatchResult.PASS; } - private Patch.Result offsetParameterIndex(AnnotationHandle annotation, Type paramType, MethodContext methodContext) { + private PatchResult offsetParameterIndex(AnnotationHandle annotation, Type paramType, MethodContext methodContext) { // Validate implicit targets for @Local parameters if (annotation.getAllValues().isEmpty()) { int compatLevel = methodContext.patchContext().environment().fabricLVTCompatibility(); if (compatLevel != FabricUtil.COMPATIBILITY_0_10_0) { - return Patch.Result.PASS; + return PatchResult.PASS; } - MethodContext.TargetPair targetPair = methodContext.findDirtyInjectionTarget(); + TargetPair targetPair = methodContext.findDirtyInjectionTarget(); if (targetPair == null) { - return Patch.Result.PASS; + return PatchResult.PASS; } - List locals = methodContext.getTargetMethodLocals(targetPair, 0, compatLevel); + List locals = methodContext.getTargetMethodLocals(targetPair, 0, compatLevel); if (locals != null && locals.stream().filter(var -> var.type() == paramType).count() > 1) { // Mixin found more locals than required, let's try to fix this // The old method might still get us the expected results - List oldCompatLocals = methodContext.getTargetMethodLocals(targetPair, 0, FabricUtil.COMPATIBILITY_0_9_2); - List sameType = oldCompatLocals.stream().filter(var -> var.type() == paramType).toList(); + List oldCompatLocals = methodContext.getTargetMethodLocals(targetPair, 0, FabricUtil.COMPATIBILITY_0_9_2); + List sameType = oldCompatLocals.stream().filter(var -> var.type() == paramType).toList(); if (sameType.size() == 1) { int index = sameType.getFirst().index(); annotation.appendValue("index", index); methodContext.recordAudit(this, "Fix @Local annotation using index %s", index); - return Patch.Result.APPLY; + return PatchResult.APPLY; } } } - return Patch.Result.PASS; + return PatchResult.PASS; } @Nullable @@ -134,7 +144,7 @@ private ParamsDiffSnapshot compareParameters(ClassNode classNode, MethodNode met // 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 - LayeredParamsDiffSnapshot rearrange = rearrangeParameters(capturedLocals.expected(), info.availableTypes()); + LayeredParamsDiffSnapshot rearrange = CapturedLocalsPreProcessor.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/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java new file mode 100644 index 00000000..0e9d28fb --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java @@ -0,0 +1,72 @@ +package org.sinytra.adapter.next.transform.preprocess; + +import com.mojang.datafixers.util.Pair; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; +import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.patch.api.PatchAuditTrail; +import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.patch.util.AdapterUtil; + +import java.util.ArrayList; +import java.util.List; + +public class LocalCaptureUpgradeTransformer implements MethodTransformer { + @Override + public PatchResult apply(MixinContext context, Configuration config) { + // Check requirements + TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), config.getTargetMethod()); + if (cleanTarget == null) return PatchResult.PASS; + + TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), config.getTargetMethod()); + if (dirtyTarget == null) return PatchResult.PASS; + + if (!config.hasProperty(Keys.LOCALS)) return PatchResult.PASS; + + // Analyze locals + MethodNode methodNode = context.methodNode(); + Type[] paramTypes = Type.getArgumentTypes(methodNode.desc); + List> localAnnotations = AdapterUtil.getAnnotatedParameters(methodNode, paramTypes, MixinConstants.LOCAL, Pair::of); + if (!localAnnotations.isEmpty()) { + return PatchResult.PASS; + } + + LocalVarAnalyzer.CapturedLocalsInfo info = LocalVarAnalyzer.getCapturedLocals(context.legacy()); + if (info == null || info.diff().isEmpty()) { + return PatchResult.PASS; + } + + 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 PatchResult.PASS; + } + availableTypes.remove(available.getFirst()); + } + + PatchResult result = transform.remover().apply(context.legacy()); + if (result == PatchResult.PASS) return PatchResult.PASS; + + int start = info.capturedLocals().paramLocalStart(); + Type[] args = Type.getArgumentTypes(methodNode.desc); + for (int i = start; i < args.length; i++) { + methodNode.visitParameterAnnotation(i, MixinConstants.LOCAL, false); + } + + PatchAuditTrail auditTrail = context.environment().auditTrail(); +// auditTrail.recordAudit(this, methodContext, "Upgrade captured locals"); + auditTrail.recordResult(context.legacy(), PatchAuditTrail.Match.FULL); + return result; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java index 43e8fada..08728396 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java @@ -3,40 +3,39 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; +import org.sinytra.adapter.next.env.param.Parameter; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.config.PropertyKey; +import org.sinytra.adapter.next.pipeline.config.*; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.ComparingInjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.next.pipeline.resolver.special.InjectorOrdinalResolver; import java.util.List; -import java.util.Set; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; -public class InjectMixin implements MixinType { - @Override - public PropertyContainerTemplate getConfigurationTemplate() { - return ConfigurationTemplates.MIXIN_AT; - } +public class InjectMixin implements MixinType { + private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + .keys(Keys.SLICES, Keys.CANCELLABLE) + .build(); @Override - public Set> requestProperties() { - return Set.of(Keys.SLICES, Keys.CANCELLABLE); + public PropertyContainerTemplate getConfigurationTemplate() { + return TEMPLATE; } @Override - public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().getOrThrow(InjectionPointResolver.class) + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers + .addBefore(InjectionPointResolver.class, new InjectorOrdinalResolver()); + resolvers.getOrThrow(InjectionPointResolver.class) .addSubResolver(new AtVariableAssignStoreSubResolver()) .addSubResolver(new ComparingInjectionPointResolver.Inject()) .addSubResolver(new ArbitraryInjectionPointSubResolver()); @@ -51,7 +50,7 @@ public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfigu } @Override - public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { dirty.setReturnType(Type.VOID_TYPE); if (dirty.getTargetMethod() == null) { return TxResult.SUCCESS; @@ -71,6 +70,19 @@ public TxResult postProcess(MixinData mixin, MixinContext context, Configuration } } + // Process static modifier + if (!clean.getProperty(SpecialKeys.STATIC).orElse(false) && dirty.getProperty(SpecialKeys.STATIC).orElse(false)) { + List types = context.targetTypes(); + if (types.size() == 1) { + MethodParameters params = dirty.getParameters(); + List methodParams = params.get(METHOD_PARAMS); + Type targetType = types.getFirst(); + methodParams.addFirst(Parameter.simple(targetType)); + } else { + throw new IllegalStateException("Cannot automatically determine target instance type for mixin " + context.classNode().name); + } + } + return TxResult.SUCCESS; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java b/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java index d6dae62d..06f623b3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java @@ -1,27 +1,21 @@ package org.sinytra.adapter.next.type; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.config.PropertyKey; - -import java.util.Set; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; /** * Handles configuration and behavior specific to a Mixin type */ -public interface MixinType { +public interface MixinType { PropertyContainerTemplate getConfigurationTemplate(); - default Set> requestProperties() { - return Set.of(); - } - - TxResult preProcess(T mixin, MixinContext context, MutableConfiguration clean, Recipe recipe); + TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors); - TxResult postProcess(T mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); + TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java b/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java index 83e56917..ee0e3732 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java @@ -11,14 +11,18 @@ import java.util.Map; public class MixinTypes { - private static final Map> MIXIN_TYPES = new HashMap<>(); + private static final Map MIXIN_TYPES = new HashMap<>(); - public static final MixinType INJECT = new InjectMixin(); - public static final MixinType MODIFY_VAR = new ModifyVariableMixin(); - public static final MixinType MODIFY_ARG = new ModifyArgMixin(); - public static final MixinType REDIRECT = new RedirectMixin(); - public static final MixinType WRAP_OP = new WrapOperationMixin(); - public static final MixinType MODIFY_EXPR_VAL = new ModifyExpressionValueMixin(); + // TODO: + // MixinConstants.MODIFY_ARGS, MixinConstants.MODIFY_CONST, MixinConstants.WRAP_WITH_CONDITION, + // MixinConstants.MODIFY_RETURN_VAL, MixinConstants.OVERWRITE (dont forget special modifyTarget handling) + // MixinConstants.ACCESSOR + public static final MixinType INJECT = new InjectMixin(); + public static final MixinType MODIFY_VAR = new ModifyVariableMixin(); + public static final MixinType MODIFY_ARG = new ModifyArgMixin(); + public static final MixinType REDIRECT = new RedirectMixin(); + public static final MixinType WRAP_OP = new WrapOperationMixin(); + public static final MixinType MODIFY_EXPR_VAL = new ModifyExpressionValueMixin(); static { registerMixinType(Inject.class, INJECT); @@ -30,16 +34,16 @@ public class MixinTypes { } @Nullable - public static MixinType getMixinType(String annotation) { + public static MixinType getMixinType(String annotation) { return MIXIN_TYPES.get(annotation); } - private static void registerMixinType(Class annotation, MixinType type) { + private static void registerMixinType(Class annotation, MixinType type) { String internalName = annotation.getName().replace('.', '/'); registerMixinType(internalName, type); } - private static void registerMixinType(String annInternalName, MixinType type) { + private static void registerMixinType(String annInternalName, MixinType type) { MIXIN_TYPES.put(annInternalName, type); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java index d1486be9..6d6b25d4 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java @@ -5,53 +5,49 @@ import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.Parameter; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.config.PropertyKey; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.fixes.TypeAdapter; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; -import java.util.Set; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; -import static org.sinytra.adapter.next.pipeline.config.Configuration.Keys.INDEX; +import static org.sinytra.adapter.next.pipeline.config.Keys.INDEX; -public class ModifyArgMixin implements MixinType { - @Override - public PropertyContainerTemplate getConfigurationTemplate() { - return ConfigurationTemplates.MIXIN_AT; - } +public class ModifyArgMixin implements MixinType { + private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + .keys(Keys.INDEX) + .build(); @Override - public Set> requestProperties() { - return Set.of(Configuration.Keys.INDEX); + public PropertyContainerTemplate getConfigurationTemplate() { + return TEMPLATE; } @Override - public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().getOrThrow(InjectionPointResolver.class) + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers.getOrThrow(InjectionPointResolver.class) .addSubResolver(new ArbitraryInjectionPointSubResolver()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY))); - mixin.getProperty(INDEX) - .ifPresent(p -> clean.setProperty(INDEX, p)); - return TxResult.SUCCESS; } @Override - public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { if (clean.getAtData().equals(dirty.getAtData())) { dirty.inheritParameters(); dirty.inheritReturnType(); @@ -69,7 +65,7 @@ public TxResult postProcess(MixinData mixin, MixinContext context, Configuration dirty.setParameters(parameters); dirty.setReturnType(type); } - + return TxResult.SUCCESS; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java index 1a306f79..008c396b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java @@ -3,13 +3,14 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; @@ -21,16 +22,18 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; -public class ModifyExpressionValueMixin implements MixinType { +public class ModifyExpressionValueMixin implements MixinType { @Override public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } @Override - public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().getOrThrow(InjectionPointResolver.class).addSubResolver(new ArbitraryInjectionPointSubResolver()); - recipe.resolvers().addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(true)); + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers.getOrThrow(InjectionPointResolver.class) + .addSubResolver(new ArbitraryInjectionPointSubResolver()); + resolvers + .addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(true)); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, CAPTURED_PARAMS))); @@ -38,7 +41,7 @@ public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfigu } @Override - public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { if (dirty.getTargetMethod() == null || dirty.getAtData() == null || !dirty.getAtData().getValue().equals(AT_VAL_INVOKE)) { return TxResult.FAIL; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyReturnValueMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyReturnValueMixin.java new file mode 100644 index 00000000..8632b1ab --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyReturnValueMixin.java @@ -0,0 +1,32 @@ +package org.sinytra.adapter.next.type; + +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.next.pipeline.TxResult; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; +import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; +import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.next.pipeline.resolver.special.InjectorOrdinalResolver; + +// TODO +public class ModifyReturnValueMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return null; + } + + @Override + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers + .addBefore(InjectionPointResolver.class, new InjectorOrdinalResolver()); + return null; + } + + @Override + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + return null; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java index 44230b6f..d3ba07e7 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java @@ -3,56 +3,58 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.Parameter; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Configuration.Keys; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.config.PropertyKey; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.ModifyVarInjectionPointSubResolver; +import org.sinytra.adapter.next.pipeline.resolver.special.InjectorOrdinalResolver; +import org.sinytra.adapter.next.pipeline.resolver.special.ModifyVarAtReturnResolver; +import org.sinytra.adapter.next.pipeline.resolver.special.ModifyVarUpgradeResolver; import org.sinytra.adapter.patch.fixes.TypeAdapter; import java.util.List; -import java.util.Set; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.LOCALS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; -public class ModifyVariableMixin implements MixinType { - @Override - public PropertyContainerTemplate getConfigurationTemplate() { - return ConfigurationTemplates.MIXIN_AT; - } +public class ModifyVariableMixin implements MixinType { + private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + .keys(Keys.ARGS_ONLY, Keys.ORDINAL, Keys.INDEX, Keys.SLICE) + .build(); @Override - public Set> requestProperties() { - return Set.of(Keys.ARGS_ONLY, Keys.ORDINAL, Keys.SLICE); + public PropertyContainerTemplate getConfigurationTemplate() { + return TEMPLATE; } @Override - public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().getOrThrow(InjectionPointResolver.class) + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers + .addFirst(new ModifyVarUpgradeResolver()) + .addBefore(InjectionPointResolver.class, new InjectorOrdinalResolver()) + .addBefore(InjectionPointResolver.class, new ModifyVarAtReturnResolver()); + resolvers.getOrThrow(InjectionPointResolver.class) .addSubResolver(new ModifyVarInjectionPointSubResolver()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, LOCALS))); - mixin.getProperty(Keys.SLICE) - .ifPresent(p -> clean.setProperty(Keys.SLICE, p)); - return TxResult.SUCCESS; } @Override - public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { dirty.inheritProperyIfAbsent(Keys.SLICE); - boolean argsOnly = mixin.getProperty(Keys.ARGS_ONLY).orElse(false); + boolean argsOnly = clean.getProperty(Keys.ARGS_ONLY).orElse(false); if (argsOnly && dirty.getTargetMethod() != null && !dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { Type cleanVarType = clean.getParameters().getTypes(SINGLE_ANY).getFirst(); List cleanTargetMethodParams = Parameters.getParameterTypes(clean.getTargetMethod().desc()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java index 778de60f..e175eee7 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java @@ -4,7 +4,6 @@ import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; @@ -12,10 +11,13 @@ import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.ParameterUsageProcessor; +import org.sinytra.adapter.next.pipeline.processor.Processors; +import org.sinytra.adapter.next.pipeline.processor.redirect.ParameterUsageProcessor; import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; +import org.sinytra.adapter.next.pipeline.processor.redirect.DivertRedirectProcessor; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; @@ -24,16 +26,19 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; -public class RedirectMixin implements MixinType { +public class RedirectMixin implements MixinType { @Override public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } @Override - public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(false)); - recipe.processors().addAfter(ParametersProcessor.class, new ParameterUsageProcessor()); + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers. + addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(false)); + processors + .addAfter(ParametersProcessor.class, new DivertRedirectProcessor()) + .addAfter(ParametersProcessor.class, new ParameterUsageProcessor()); if (clean.getAtData() == null || !MixinAnnotationConstants.AT_VAL_INVOKE.equals(clean.getAtData().getValue())) return TxResult.FAIL; @@ -57,7 +62,7 @@ public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfigu } @Override - public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { if (dirty.getTargetMethod() == null) return TxResult.FAIL; diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java index 394913f8..bf607b00 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java @@ -4,17 +4,19 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinData; import org.sinytra.adapter.next.env.ctx.MethodHelper; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; +import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.processor.wrapop.WrapOpParamsProcessor; +import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.ComparingInjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; @@ -26,9 +28,9 @@ import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; -public class WrapOperationMixin implements MixinType { +public class WrapOperationMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_BASE.extend() - .requireOne(Configuration.Keys.TARGET_AT, Configuration.Keys.TARGET_CONSTANT) + .requireOne(Keys.TARGET_AT, Keys.TARGET_CONSTANT) .build(); @Override @@ -37,11 +39,11 @@ public PropertyContainerTemplate getConfigurationTemplate() { } @Override - public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfiguration clean, Recipe recipe) { - recipe.resolvers().getOrThrow(InjectionPointResolver.class) + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers.getOrThrow(InjectionPointResolver.class) .addSubResolverFirst(new ComparingInjectionPointResolver.WrapOperation()) .addSubResolver(new AtVariableAssignStoreSubResolver()); - recipe.processors() + processors .addAfter(ParametersProcessor.class, new WrapOpParamsProcessor()); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(METHOD_PARAMS, OPERATION, CAPTURED_PARAMS, LOCALS))); @@ -50,7 +52,7 @@ public TxResult preProcess(MixinData mixin, MixinContext context, MutableConfigu } @Override - public TxResult postProcess(MixinData mixin, MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { if (dirty.getTargetMethod() == null) return TxResult.FAIL; if (dirty.getAtData() == null) return TxResult.PASS; diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java index 63ba4cca..95b3d4ff 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java @@ -4,11 +4,11 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.transform.preprocess.CapturedLocalsPreProcessor; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.params.ParametersDiff; import org.sinytra.adapter.patch.test.mixin.MinecraftMixinPatchTest; -import org.sinytra.adapter.patch.transformer.dynamic.DynamicLVTPatch; import java.io.IOException; import java.util.Deque; @@ -149,7 +149,7 @@ public void testCompareReorderedParameters() { Type[] original = new Type[]{Type.getType(String.class), Type.getType(List.class), Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE, Type.getType(Set.class), Type.getType(Map.class)}; Type[] modified = new Type[]{Type.getType(String.class), Type.getType(List.class), Type.getType(Deque.class), Type.getType(Map.class), Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE, Type.getType(Set.class)}; - LayeredParamsDiffSnapshot diff = DynamicLVTPatch.rearrangeParameters(List.of(original), List.of(modified)); + LayeredParamsDiffSnapshot diff = CapturedLocalsPreProcessor.rearrangeParameters(List.of(original), List.of(modified)); System.out.println("Insertions:"); diff.insertions().forEach(param -> System.out.println("AT " + param.getFirst() + " TYPE " + param.getSecond())); 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 853c3cf7..1e01946f 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 @@ -5,12 +5,11 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.next.PipelineLegacyMethodTransformer; -import org.sinytra.adapter.patch.api.Patch; +import org.sinytra.adapter.next.flow.DynamicPatches; +import org.sinytra.adapter.next.flow.Patcher; 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.dynamic.LocalCaptureUpgradePreprocessor; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.slf4j.Logger; import org.spongepowered.asm.mixin.FabricUtil; @@ -18,15 +17,9 @@ import java.util.List; public class DynamicMixinPatchTest extends MinecraftMixinPatchTest { - private static final List DYNAMIC_PATCHES = List.of( - Patch.builder() - .transform(new LocalCaptureUpgradePreprocessor()) - .transform(new PipelineLegacyMethodTransformer()) - .transform(new FieldTypeUsageTransformer()) - .build() - ); private static final Logger LOGGER = LogUtils.getLogger(); + private static Patcher patcher; private static PatchEnvironment patchEnvironment; @BeforeAll @@ -49,6 +42,12 @@ public void copyEntries(String from, String to) { new BytecodeFixerUpperTestFrontend(cleanLookup, dirtyLookup).unwrap(), FabricUtil.COMPATIBILITY_LATEST ); + patcher = new Patcher( + patchEnvironment, + List.of(new FieldTypeUsageTransformer()), + DynamicPatches.methodTransformers(List.of()), + List.of() + ); } @AfterAll @@ -430,9 +429,9 @@ void testSyntheticInstanceofMEV() throws Exception { @Override protected LoadResult load(String className, List allowedMethods) throws Exception { - final ClassNode patched = loadClass(className); + ClassNode patched = loadClass(className); patched.methods.removeIf(m -> !allowedMethods.contains(m.name)); - DYNAMIC_PATCHES.forEach(p -> p.apply(patched, patchEnvironment)); + patcher.apply(patched); return new LoadResult(patchEnvironment, patched, loadClass(className)); } } From 3fbc9a09823e032f8201a963de337097178c299e Mon Sep 17 00:00:00 2001 From: Su5eD Date: Mon, 26 Jan 2026 21:38:50 +0100 Subject: [PATCH 07/27] Migrate away from MethodContext --- .../adapter/patch/MethodContextImpl.java | 405 ------------------ .../patch/analysis/MethodLabelComparator.java | 14 +- .../analysis/locals/LocalVarAnalyzer.java | 34 +- .../patch/analysis/method/MethodAnalyzer.java | 15 +- .../analysis/method/MethodCallAnalyzer.java | 7 +- .../params/LayeredParamsDiffSnapshot.java | 2 +- .../analysis/params/ParamsDiffSnapshot.java | 7 +- .../selector/InjectionPointMatcher.java | 44 -- .../analysis/selector/MethodMatcher.java | 19 - .../adapter/patch/api/MethodContext.java | 71 --- .../operation/param/ParameterTransformer.java | 14 - .../adapter/patch/util/AdapterUtil.java | 41 +- .../adapter/patch/util/MethodQualifier.java | 2 +- .../next/env/ConfigurationTemplates.java | 2 +- .../adapter/next/env/MixinContext.java | 51 +-- .../adapter/next/env}/MockMixinRuntime.java | 6 +- .../sinytra/adapter/next/env/ann/AtData.java | 6 +- .../adapter/next/env/ann/ClassTarget.java | 4 +- .../adapter/next/env/ann/SliceData.java | 12 +- .../adapter/next/env/ctx/AuditTrail.java} | 25 +- .../adapter/next/env/ctx/AuditTrailImpl.java} | 36 +- .../adapter/next/env/ctx}/LocalVariable.java | 2 +- .../adapter/next/env/ctx/MethodFinder.java | 1 - .../adapter/next/env/ctx/MethodHelper.java | 46 +- .../next/env/ctx}/MixinClassGenerator.java | 2 +- .../env/ctx}/MixinClassGeneratorImpl.java | 7 +- .../adapter/next/env/ctx}/PatchContext.java | 3 +- .../next/env/ctx}/PatchContextImpl.java | 4 +- .../next/env/ctx}/PatchEnvironment.java | 9 +- .../next/env/ctx}/PatchEnvironmentImpl.java | 14 +- .../adapter/next/env/ctx}/PatchResult.java | 2 +- .../adapter/next/env/ctx}/RefmapHolder.java | 2 +- .../adapter/next/env/ctx}/TargetPair.java | 2 +- .../next/env/param/MethodParameters.java | 6 +- .../adapter/next/env/param/Parameter.java | 4 +- .../MixinAnnotationConstants.java | 2 +- .../next/env/util/MixinAnnotations.java} | 19 +- .../next/env/{ => util}/OrderedRegistry.java | 2 +- .../adapter/next/env/util/TypeConstants.java | 16 + .../env/{ => util}/WeighedDisambiguation.java | 2 +- .../adapter/next/flow/DynamicPatches.java | 6 +- .../adapter/next/flow/MixinParser.java | 32 +- .../sinytra/adapter/next/flow/Patcher.java | 34 +- .../next/{type => mixin}/InjectMixin.java | 2 +- .../next/{type => mixin}/MixinType.java | 2 +- .../next/{type => mixin}/MixinTypes.java | 8 +- .../next/{type => mixin}/ModifyArgMixin.java | 8 +- .../ModifyExpressionValueMixin.java | 6 +- .../ModifyReturnValueMixin.java | 2 +- .../{type => mixin}/ModifyVariableMixin.java | 4 +- .../next/{type => mixin}/RedirectMixin.java | 8 +- .../{type => mixin}/WrapOperationMixin.java | 8 +- .../pipeline/PipelineMethodTransformer.java | 69 ++- .../sinytra/adapter/next/pipeline/Recipe.java | 108 ++++- .../config/BasePropertyContainer.java | 21 +- .../adapter/next/pipeline/config/Keys.java | 3 +- .../config/MutablePropertyContainer.java | 5 + .../processor/InjectionTargetProcessor.java | 8 +- .../processor/ParametersProcessor.java | 4 +- .../next/pipeline/processor/Processors.java | 2 +- .../processor/ReturnTypeProcessor.java | 2 +- .../processor/TargetMethodProcessor.java | 23 +- .../processor/extract/ExtractMixin.java | 351 --------------- .../extract/ExtractMixinProcessor.java | 354 ++++++++++++++- .../extract/MirrorableExtractMixin.java | 53 ++- .../redirect/DivertRedirectProcessor.java | 4 +- .../redirect/ParameterUsageProcessor.java | 4 +- .../processor/wrapop/WrapOpSurgeon.java | 8 +- .../next/pipeline/resolver/Resolvers.java | 2 +- .../ArbitraryInjectionPointSubResolver.java | 8 +- .../AtVariableAssignStoreSubResolver.java | 14 +- .../ComparingInjectionPointResolver.java | 28 +- .../InheritedInjectionPointSubResolver.java | 16 +- .../injection/InjectionPointResolver.java | 2 +- .../injection/InjectionPointSubResolvers.java | 6 +- .../ModifyVarInjectionPointSubResolver.java | 4 +- .../special/InjectorOrdinalResolver.java | 19 +- .../special/ModifyVarAtReturnResolver.java | 12 +- .../special/ModifyVarUpgradeResolver.java | 8 +- .../special/ResolverSyntheticInstanceof.java | 10 +- .../special/SliceBoundaryResolver.java | 8 +- .../target/SplitMethodCancellationHelper.java | 19 +- .../target/SplitTargetMethodSubResolver.java | 6 +- .../resolver/target/TargetMethodResolver.java | 2 +- .../target/TargetMethodSubResolvers.java | 4 +- .../next/transform/ClassTransformer.java | 4 +- .../next/transform/MethodTransformer.java | 2 +- .../cls/DynamicAnonClassIndexPatch.java | 10 +- .../DynamicAnonymousShadowFieldTypePatch.java | 6 +- .../param/InjectParameterTransform.java | 17 +- .../param/InlineParameterTransformer.java | 11 +- .../param/ModifyArgsOffsetUpgrader.java | 2 +- .../param/MoveParametersTransformer.java | 9 +- .../param/ParamTransformationUtil.java | 11 +- .../transform/param/ParameterTransformer.java | 13 + .../param/RemoveParameterTransformer.java | 11 +- .../param/ReplaceParametersTransformer.java | 18 +- .../param/SubstituteParameterTransformer.java | 21 +- .../param/SwapParametersTransformer.java | 11 +- .../transform}/param/TransformParameters.java | 39 +- .../patch/MethodPatchBuilderImpl.java | 4 +- .../patch/MethodPatchTransformer.java | 2 +- .../CapturedLocalsPreProcessor.java | 263 ------------ .../LocalCaptureUpgradeTransformer.java | 33 +- .../types}/BytecodeFixerJarGenerator.java | 2 +- .../next/types}/BytecodeFixerUpper.java | 2 +- .../FieldAccessorTypeTransformer.java | 16 +- .../types}/FieldTypeUsageTransformer.java | 6 +- .../next/types}/ObjectTypeAdapter.java | 2 +- .../next/types}/SimpleTypeAdapter.java | 2 +- .../next/types}/SupplierTypeAdapter.java | 2 +- .../adapter/next/types}/TypeAdapter.java | 2 +- .../next/types}/TypeAdapterProvider.java | 2 +- .../patch/test/ParameterComparisonTest.java | 28 -- .../mixin/BytecodeFixerUpperTestFrontend.java | 6 +- .../test/mixin/DynamicMixinPatchTest.java | 9 +- .../test/mixin/MinecraftMixinPatchTest.java | 10 +- 117 files changed, 1082 insertions(+), 1763 deletions(-) delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/InjectionPointMatcher.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/MethodMatcher.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/api/MethodContext.java delete mode 100644 definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java rename definition/src/{main/java/org/sinytra/adapter/patch/util => next/java/org/sinytra/adapter/next/env}/MockMixinRuntime.java (98%) rename definition/src/{main/java/org/sinytra/adapter/patch/api/PatchAuditTrail.java => next/java/org/sinytra/adapter/next/env/ctx/AuditTrail.java} (67%) rename definition/src/{main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java => next/java/org/sinytra/adapter/next/env/ctx/AuditTrailImpl.java} (81%) rename definition/src/{main/java/org/sinytra/adapter/patch/api => next/java/org/sinytra/adapter/next/env/ctx}/LocalVariable.java (67%) rename definition/src/{main/java/org/sinytra/adapter/patch/api => next/java/org/sinytra/adapter/next/env/ctx}/MixinClassGenerator.java (90%) rename definition/src/{main/java/org/sinytra/adapter/patch => next/java/org/sinytra/adapter/next/env/ctx}/MixinClassGeneratorImpl.java (91%) rename definition/src/{main/java/org/sinytra/adapter/patch/api => next/java/org/sinytra/adapter/next/env/ctx}/PatchContext.java (84%) rename definition/src/{main/java/org/sinytra/adapter/patch => next/java/org/sinytra/adapter/next/env/ctx}/PatchContextImpl.java (89%) rename definition/src/{main/java/org/sinytra/adapter/patch/api => next/java/org/sinytra/adapter/next/env/ctx}/PatchEnvironment.java (81%) rename definition/src/{main/java/org/sinytra/adapter/patch => next/java/org/sinytra/adapter/next/env/ctx}/PatchEnvironmentImpl.java (75%) rename definition/src/{main/java/org/sinytra/adapter/patch/api => next/java/org/sinytra/adapter/next/env/ctx}/PatchResult.java (88%) rename definition/src/{main/java/org/sinytra/adapter/patch/api => next/java/org/sinytra/adapter/next/env/ctx}/RefmapHolder.java (75%) rename definition/src/{main/java/org/sinytra/adapter/patch/api => next/java/org/sinytra/adapter/next/env/ctx}/TargetPair.java (79%) rename definition/src/next/java/org/sinytra/adapter/next/env/{ann => util}/MixinAnnotationConstants.java (95%) rename definition/src/{main/java/org/sinytra/adapter/patch/api/MixinConstants.java => next/java/org/sinytra/adapter/next/env/util/MixinAnnotations.java} (73%) rename definition/src/next/java/org/sinytra/adapter/next/env/{ => util}/OrderedRegistry.java (98%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/util/TypeConstants.java rename definition/src/next/java/org/sinytra/adapter/next/env/{ => util}/WeighedDisambiguation.java (97%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/InjectMixin.java (99%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/MixinType.java (95%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/MixinTypes.java (86%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/ModifyArgMixin.java (95%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/ModifyExpressionValueMixin.java (94%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/ModifyReturnValueMixin.java (96%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/ModifyVariableMixin.java (97%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/RedirectMixin.java (94%) rename definition/src/next/java/org/sinytra/adapter/next/{type => mixin}/WrapOperationMixin.java (94%) delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixin.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/InjectParameterTransform.java (84%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/InlineParameterTransformer.java (83%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/ModifyArgsOffsetUpgrader.java (96%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/MoveParametersTransformer.java (86%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/ParamTransformationUtil.java (84%) create mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/param/ParameterTransformer.java rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/RemoveParameterTransformer.java (81%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/ReplaceParametersTransformer.java (85%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/SubstituteParameterTransformer.java (59%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/SwapParametersTransformer.java (87%) rename definition/src/{main/java/org/sinytra/adapter/patch/transformer/operation => next/java/org/sinytra/adapter/next/transform}/param/TransformParameters.java (75%) delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/BytecodeFixerJarGenerator.java (99%) rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/BytecodeFixerUpper.java (98%) rename definition/src/next/java/org/sinytra/adapter/next/{transform => types}/FieldAccessorTypeTransformer.java (91%) rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/FieldTypeUsageTransformer.java (97%) rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/ObjectTypeAdapter.java (96%) rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/SimpleTypeAdapter.java (94%) rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/SupplierTypeAdapter.java (97%) rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/TypeAdapter.java (89%) rename definition/src/{main/java/org/sinytra/adapter/patch/fixes => next/java/org/sinytra/adapter/next/types}/TypeAdapterProvider.java (74%) diff --git a/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java b/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java deleted file mode 100644 index c3eb3df1..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/MethodContextImpl.java +++ /dev/null @@ -1,405 +0,0 @@ -package org.sinytra.adapter.patch; - -import com.google.common.base.Suppliers; -import com.mojang.datafixers.util.Pair; -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.*; -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.*; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.MockMixinRuntime; -import org.sinytra.adapter.patch.util.provider.ClassLookup; -import org.slf4j.Logger; -import org.spongepowered.asm.mixin.injection.InjectionPoint; -import org.spongepowered.asm.mixin.injection.code.ISliceContext; -import org.spongepowered.asm.mixin.injection.code.MethodSlice; -import org.spongepowered.asm.mixin.injection.points.BeforeConstant; -import org.spongepowered.asm.mixin.injection.struct.Target; -import org.spongepowered.asm.mixin.refmap.IMixinContext; -import org.spongepowered.asm.util.Locals; - -import java.util.*; -import java.util.function.BiFunction; -import java.util.function.Supplier; -import java.util.stream.Stream; - -public final class MethodContextImpl implements MethodContext { - private static final Logger LOGGER = LogUtils.getLogger(); - private final ClassNode classNode; - private final AnnotationHandle rawClassAnnotation; - private final AnnotationValueHandle classAnnotation; - private final MethodNode methodNode; - private final AnnotationHandle methodAnnotation; - private final @Nullable AnnotationHandle injectionPointAnnotation; - private final List targetTypes; - private final PatchContext patchContext; - - private final Supplier cleanInjectionPairCache; - private final Supplier dirtyInjectionPairCache; - private final Supplier cleanLocalsTableCache; - private final Supplier dirtyLocalsTableCache; - private final Map> targetInstructionsCache; - - public MethodContextImpl(ClassNode classNode, AnnotationHandle rawClassAnnotation, AnnotationValueHandle classAnnotation, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation, List targetTypes, PatchContext patchContext) { - this.classNode = Objects.requireNonNull(classNode, "Missing class node"); - this.rawClassAnnotation = Objects.requireNonNull(rawClassAnnotation, "Missing raw class annotation"); - this.classAnnotation = Objects.requireNonNull(classAnnotation, "Missing class annotation"); - this.methodNode = Objects.requireNonNull(methodNode, "Missing method node"); - this.methodAnnotation = Objects.requireNonNull(methodAnnotation, "Missing method annotation"); - this.injectionPointAnnotation = injectionPointAnnotation; - this.targetTypes = Objects.requireNonNull(targetTypes, "Missing target types"); - this.patchContext = patchContext; - - this.cleanInjectionPairCache = Suppliers.memoize(() -> { - ClassLookup cleanClassLookup = this.patchContext.environment().cleanClassLookup(); - return findInjectionTarget(cleanClassLookup); - }); - this.dirtyInjectionPairCache = Suppliers.memoize(() -> findInjectionTarget(this.patchContext.environment().dirtyClassLookup())); - this.targetInstructionsCache = new HashMap<>(); - this.cleanLocalsTableCache = Suppliers.memoize(() -> Optional.ofNullable(findCleanInjectionTarget()).map(pair -> new LocalVariableLookup(pair.methodNode())).orElse(null)); - this.dirtyLocalsTableCache = Suppliers.memoize(() -> Optional.ofNullable(findDirtyInjectionTarget()).map(pair -> new LocalVariableLookup(pair.methodNode())).orElse(null)); - } - - @Override - public TargetPair findCleanInjectionTarget() { - return this.cleanInjectionPairCache.get(); - } - - @Override - public TargetPair findDirtyInjectionTarget() { - return this.dirtyInjectionPairCache.get(); - } - - @Override - public LocalVariableLookup cleanLocalsTable() { - return this.cleanLocalsTableCache.get(); - } - - @Override - public LocalVariableLookup dirtyLocalsTable() { - return this.dirtyLocalsTableCache.get(); - } - - @Nullable - @Override - public MethodQualifier getTargetMethodQualifier() { - // Get method targets - List methodRefs = methodAnnotation().>getValue("method").map(AnnotationValueHandle::get).orElseGet(Collections::emptyList); - if (methodRefs.size() != 1) { - // We only support single method targets for now - return null; - } - // Resolve method reference - String reference = patchContext().remap(methodRefs.getFirst()); - // Extract owner, name and desc using regex - return MethodQualifier.create(reference).orElse(null); - } - - @Override - public List findInjectionTargetInsns(@Nullable TargetPair target) { - return this.targetInstructionsCache.computeIfAbsent(target, this::computeInjectionTargetInsns); - } - - @Override - public void updateDescription(List parameters) { - Type returnType = Type.getReturnType(this.methodNode.desc); - String newDesc = Type.getMethodDescriptor(returnType, parameters.toArray(Type[]::new)); -// recordAudit(transform, "Change descriptor to %s", newDesc); - this.methodNode.desc = newDesc; - this.methodNode.signature = null; - } - - @Override - public boolean isStatic() { - return (this.methodNode.access & Opcodes.ACC_STATIC) != 0; - } - - @Nullable - @Override - public List getTargetMethodLocals(TargetPair target) { - Type[] targetParams = Type.getArgumentTypes(target.methodNode().desc); - boolean isStatic = (this.methodNode.access & Opcodes.ACC_STATIC) != 0; - int lvtOffset = isStatic ? 0 : 1; - // The starting LVT index is of the first var after all method parameters. Offset by 1 for instance methods to skip 'this' - int targetLocalPos = targetParams.length + lvtOffset; - return getTargetMethodLocals(target, targetLocalPos); - } - - @Nullable - @Override - public List getTargetMethodLocals(TargetPair target, int startPos, int lvtCompatLevel) { - List targetInsns = findInjectionTargetInsns(target); - if (targetInsns.isEmpty()) { - LOGGER.debug("Skipping LVT patch, no target instructions found"); - return null; - } - // Get available local variables at the injection point in the target method - LocalVariableNode[] localVariables; - // Synchronize to avoid issues in mixin. This is necessary. - synchronized (this) { - localVariables = Locals.getLocalsAt(target.classNode(), target.methodNode(), targetInsns.getFirst(), lvtCompatLevel); - } - LocalVariable[] locals = Stream.of(localVariables) - .filter(Objects::nonNull) - .map(lv -> new LocalVariable(lv.index, Type.getType(lv.desc))) - .toArray(LocalVariable[]::new); - return AdapterUtil.summariseLocals(locals, startPos); - } - - @Nullable - public List computeInjectionTargetInsns(@Nullable TargetPair target) { - return computeInjectionTargetInsns(target, this::injectionPointAnnotation, (ctx, h) -> InjectionPoint.parse(ctx, this.methodNode, methodAnnotation().unwrap(), h.unwrap())); - } - - private List computeConstantTargetInsns(@Nullable TargetPair target) { - return computeInjectionTargetInsns(target, () -> methodAnnotation().getNested("constant").orElse(null), (ctx, h) -> new BeforeConstant(ctx, h.unwrap(), Type.getReturnType(this.methodNode.desc).getDescriptor())); - } - - @Nullable - private List computeInjectionTargetInsns(@Nullable TargetPair target, Supplier atNodeSupplier, BiFunction injectionPointParser) { - if (target == null) { - return List.of(); - } - AnnotationHandle atNode = atNodeSupplier.get(); - if (atNode == null) { - return List.of(); - } - // Provide a minimum implementation of IMixinContext - IMixinContext mixinContext = MockMixinRuntime.forClass(this.classNode.name, target.classNode().name, patchContext().environment()); - // Parse injection point - InjectionPoint injectionPoint = injectionPointParser.apply(mixinContext, atNode); - Target mixinTarget = MockMixinRuntime.createMixinTarget(target); - // Find target instructions - InsnList instructions = getSlicedInsns(methodAnnotation(), this.classNode, this.methodNode, target.classNode(), target.methodNode(), patchContext(), mixinTarget); - List targetInsns = new ArrayList<>(); - try { - if (MockMixinRuntime.injectionPointNeedsSpecialCare(injectionPoint)) { - MockMixinRuntime.findModifyVariableInjectionInsns(injectionPoint, mixinContext, target.methodNode().instructions, targetInsns, mixinTarget); - } else { - injectionPoint.find(target.methodNode().desc, instructions, targetInsns); - } - } catch (Throwable e) { - LOGGER.error("Error finding injection insns", e); - return List.of(); - } - return targetInsns; - } - - @Override - public List getLvtCompatLevelsOrdered() { - int currentLevel = patchContext().environment().fabricLVTCompatibility(); - return MixinConstants.LVT_COMPATIBILITY_LEVELS.stream() - .sorted(Comparator.comparingInt(i -> i == currentLevel ? 1 : 0)) - .toList(); - } - - @Override - public boolean failsDirtyInjectionCheck() { - TargetPair dirtyPair = findDirtyInjectionTarget(); - return dirtyPair == null || computeInjectionTargetInsns(dirtyPair).isEmpty() && computeConstantTargetInsns(dirtyPair).isEmpty(); - } - - @Override - public boolean isNotRequired() { - return this.methodAnnotation.getValue("require") - .map(v -> v.get() == 0) - .orElse(false); - } - - @Override - public boolean hasValidSlice(TargetPair target) { - if (target == null) { - return false; - } - - AnnotationHandle ann = this.methodAnnotation.getValue("slice") - .map(handle -> { - Object value = handle.get(); - return value instanceof List list ? (AnnotationNode) list.getFirst() : (AnnotationNode) value; - }) - .map(AnnotationHandle::new) - .orElse(null); - if (ann == null) { - return true; - } - - AnnotationNode from = ann.getNested("from").map(AnnotationHandle::unwrap).orElse(null); - if (from != null && !validateAtNode(from, target)) { - return false; - } - - AnnotationNode to = ann.getNested("to").map(AnnotationHandle::unwrap).orElse(null); - return to == null || validateAtNode(to, target); - } - - private boolean validateAtNode(AnnotationNode at, TargetPair target) { - List insns = computeInjectionTargetInsns( - target, - this::injectionPointAnnotation, - (ctx, h) -> InjectionPoint.parse(ctx, this.methodNode, methodAnnotation().unwrap(), at) - ); - return !insns.isEmpty(); - } - - @Override - public void recordAudit(Object transform, String message, Object... args) { - this.patchContext.environment().auditTrail().recordAudit(transform, this, message, args); - } - - private InsnList getSlicedInsns(AnnotationHandle parentAnnotation, ClassNode classNode, MethodNode injectorMethod, ClassNode targetClass, MethodNode targetMethod, PatchContext context, Target mixinTarget) { - return parentAnnotation.getValue("slice") - .map(handle -> { - Object value = handle.get(); - return value instanceof List list ? (AnnotationNode) list.getFirst() : (AnnotationNode) value; - }) - .map(sliceAnn -> { - IMixinContext mixinContext = MockMixinRuntime.forClass(classNode.name, targetClass.name, context.environment()); - ISliceContext sliceContext = MockMixinRuntime.forSlice(mixinContext, injectorMethod); - return computeSlicedInsns(sliceContext, sliceAnn, mixinTarget); - }) - .orElse(targetMethod.instructions); - } - - private InsnList computeSlicedInsns(ISliceContext context, AnnotationNode annotation, Target mixinTarget) { - MethodSlice slice = MethodSlice.parse(context, annotation); - return slice.getSlice(mixinTarget); - } - - @Nullable - private TargetPair findInjectionTarget(ClassLookup lookup) { - Pair> pair = findInjectionTargetCandidates(lookup, false); - if (pair == null) { - return null; - } - - MethodQualifier qualifier = getTargetMethodQualifier(); - if (pair.getSecond().isEmpty()) { - LOGGER.debug("Target method not found: {}{}{}", qualifier.owner(), qualifier.name(), qualifier.desc()); - return null; - } else if (pair.getSecond().size() > 1) { - LOGGER.debug("Multiple candidates found for method: {}{}{}", qualifier.owner(), qualifier.name(), qualifier.desc()); - return null; - } - return new TargetPair(pair.getFirst(), pair.getSecond().getFirst()); - } - - @Nullable - public Pair> findInjectionTargetCandidates(ClassLookup lookup, boolean ignoreDesc) { - // Find target method qualifier - MethodQualifier qualifier = getTargetMethodQualifier(); - if (qualifier == null || qualifier.name() == null) { - return null; - } - String owner = Optional.ofNullable(qualifier.internalOwnerName()) - .orElseGet(() -> { - List targetTypes = this.targetTypes; - if (targetTypes.size() == 1) { - return targetTypes.getFirst().getInternalName(); - } - return null; - }); - if (owner == null) { - return null; - } - // Find target class - ClassNode targetClass = lookup.getClass(owner).orElse(null); - if (targetClass == null) { - return null; - } - // Find target method in class - String desc = qualifier.desc(); - List candidates = targetClass.methods.stream() - .filter(mtd -> mtd.name.equals(qualifier.name()) && (ignoreDesc || desc == null || mtd.desc.equals(desc))) - .toList(); - // If there's multiple candidates, try removing bouncer methods - if (candidates.size() > 1 && desc == null) { - candidates = candidates.stream().filter(mtd -> (mtd.access & Opcodes.ACC_SYNTHETIC) == 0 && (mtd.access & Opcodes.ACC_BRIDGE) == 0).toList(); - } - return Pair.of(targetClass, candidates); - } - - public static Builder builder() { - return new Builder(); - } - - @Override - public ClassNode getMixinClass() { - return this.classNode; - } - - @Override - public MethodNode getMixinMethod() { - return this.methodNode; - } - - @Override - public AnnotationHandle methodAnnotation() { - return this.methodAnnotation; - } - - @Override - @Nullable - public AnnotationHandle injectionPointAnnotation() { - return this.injectionPointAnnotation; - } - - @Override - public PatchContext patchContext() { - return this.patchContext; - } - - public static class Builder { - private ClassNode classNode; - private AnnotationHandle rawClassAnnotation; - private AnnotationValueHandle classAnnotation; - private MethodNode methodNode; - private AnnotationHandle methodAnnotation; - private AnnotationHandle injectionPointAnnotation; - private final List targetTypes = new ArrayList<>(); - - public Builder classNode(ClassNode classNode) { - this.classNode = classNode; - return this; - } - - public Builder rawClassAnnotation(AnnotationHandle annotation) { - this.rawClassAnnotation = annotation; - return this; - } - - public Builder classAnnotation(AnnotationValueHandle annotation) { - this.classAnnotation = annotation; - return this; - } - - public Builder methodNode(MethodNode methodNode) { - this.methodNode = methodNode; - return this; - } - - public Builder methodAnnotation(AnnotationHandle annotation) { - this.methodAnnotation = annotation; - return this; - } - - public Builder injectionPointAnnotation(AnnotationHandle annotation) { - this.injectionPointAnnotation = annotation; - return this; - } - - public Builder targetTypes(List targetTypes) { - this.targetTypes.addAll(targetTypes); - return this; - } - - public MethodContextImpl build(PatchContext context) { - return new MethodContextImpl(this.classNode, this.rawClassAnnotation, this.classAnnotation, this.methodNode, this.methodAnnotation, this.injectionPointAnnotation, List.copyOf(this.targetTypes), context); - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodLabelComparator.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodLabelComparator.java index 24f4b7a4..38f582b5 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodLabelComparator.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodLabelComparator.java @@ -6,7 +6,8 @@ import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.pipeline.Recipe; import java.util.*; import java.util.stream.Stream; @@ -16,8 +17,13 @@ public record ComparisonResult(List> patchedLabels, List< } @Nullable - public static ComparisonResult findPatchedLabels(AbstractInsnNode cleanInjectionInsn, MethodContext methodContext) { - List> cleanLabels = getLabelsInMethod(methodContext.findCleanInjectionTarget().methodNode()); + public static ComparisonResult findPatchedLabels(AbstractInsnNode cleanInjectionInsn, Recipe recipe) { + TargetPair cleanTarget = recipe.getCleanTarget(); + if (cleanTarget == null) return null; + TargetPair dirtyTarget = recipe.getDirtyTarget(); + if (dirtyTarget == null) return null; + + List> cleanLabels = getLabelsInMethod(cleanTarget.methodNode()); List> cleanLabelsOriginal = List.copyOf(cleanLabels); List> cleanMatchedLabels = cleanLabels.stream() @@ -28,7 +34,7 @@ public static ComparisonResult findPatchedLabels(AbstractInsnNode cleanInjection } List cleanLabel = cleanMatchedLabels.getFirst(); - List> dirtyLabels = getLabelsInMethod(methodContext.findDirtyInjectionTarget().methodNode()); + List> dirtyLabels = getLabelsInMethod(dirtyTarget.methodNode()); List> dirtyLabelsOriginal = List.copyOf(dirtyLabels); Map, List> matchedLabels = new LinkedHashMap<>(); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java index 8bee0f64..de70b9d0 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java @@ -7,11 +7,12 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; -import org.sinytra.adapter.patch.api.LocalVariable; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; +import org.sinytra.adapter.next.env.ctx.LocalVariable; +import org.sinytra.adapter.next.transform.param.TransformParameters; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -23,19 +24,18 @@ public final class LocalVarAnalyzer { - public record CapturedLocalsInfo(AdapterUtil.CapturedLocals capturedLocals, ParamsDiffSnapshot diff, List availableTypes) {} - + 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; - } + public static CapturedLocalsInfo getCapturedLocals(MixinContext context, TargetPair dirtyTarget) { + AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(context, dirtyTarget); + 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 available = context.methods().getTargetMethodLocals(capturedLocals.target()); + if (available == null) return null; + List availableTypes = available.stream().map(LocalVariable::type).toList(); // Compare expected and available params ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(capturedLocals.expected(), availableTypes); @@ -61,7 +61,8 @@ public static InsnList findInitializerInsns(MethodNode methodNode, int index) { return insns; } - public record CapturedLocalsUsage(LocalVariableLookup targetTable, Int2IntMap usageCount, Int2ObjectMap varInsnLists) {} + public record CapturedLocalsUsage(LocalVariableLookup targetTable, Int2IntMap usageCount, Int2ObjectMap varInsnLists) { + } public record CapturedLocalsTransform(List used, TransformParameters remover, List usedLocalNodes) { public CapturedLocalsUsage getUsage(AdapterUtil.CapturedLocals capturedLocals) { @@ -131,5 +132,6 @@ public static void findVariableInitializerInsns(MethodNode methodNode, boolean i varInsnLists.put(index, insns); } - private LocalVarAnalyzer() {} + private LocalVarAnalyzer() { + } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java index cc87ea8e..9257bca7 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java @@ -7,7 +7,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.analysis.*; -import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.next.env.util.TypeConstants; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -22,17 +22,8 @@ public class MethodAnalyzer { public static final String LAMBDA_PREFIX = "lambda$"; public static boolean isDirtyDeprecatedMethod(MethodNode clean, MethodNode dirty) { - return !AdapterUtil.hasAnnotation(clean.visibleAnnotations, MixinConstants.DEPRECATED) && AdapterUtil.hasAnnotation(dirty.visibleAnnotations, MixinConstants.DEPRECATED); - } - - public static List getMethodInvocations(MethodNode method, MethodQualifier qualifier) { - List list = new ArrayList<>(); - for (AbstractInsnNode insn : method.instructions) { - if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { - list.add(minsn); - } - } - return list; + return !AdapterUtil.hasAnnotation(clean.visibleAnnotations, TypeConstants.DEPRECATED) + && AdapterUtil.hasAnnotation(dirty.visibleAnnotations, TypeConstants.DEPRECATED); } @Nullable diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java index 0fe0c1d0..2830ad66 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java @@ -9,12 +9,14 @@ import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; +import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.selector.FrameUtil; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; public class MethodCallAnalyzer { @@ -45,7 +47,8 @@ public static List> getAllMethodCallSrcInsnsInclusive(Met @Nullable public static List getMethodCallSrcInsns(MethodNode methodNode, MethodInsnNode minsn) { - List sources = getCallSourceValues(methodNode, minsn); + List sources = Objects.requireNonNull(getCallSourceValues(methodNode, minsn)); + List insns = new ArrayList<>(); for (SourceValue src : sources) { AbstractInsnNode srcInsn = AdapterUtil.getSingleInsn(src); @@ -115,7 +118,7 @@ public List getResults() { @Override public SourceValue naryOperation(AbstractInsnNode insn, List values) { - if (insn == this.targetInsn && this.results == null) { + if (InsnComparator.insnEqual(insn, this.targetInsn) && this.results == null) { this.results = values; } return super.naryOperation(insn, values); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java index a97e7d44..d20cec59 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java @@ -5,7 +5,7 @@ import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.patch.transformer.operation.param.*; +import org.sinytra.adapter.next.transform.param.*; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java index 53731ad7..8d804f68 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java @@ -3,9 +3,8 @@ import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; +import org.sinytra.adapter.next.transform.param.TransformParameters; -import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; @@ -35,9 +34,5 @@ enum Flags { ParamsDiffSnapshot offset(int offset, int limit); - default TransformParameters asParameterTransformer(boolean withOffset) { - return asParameterTransformer(withOffset, EnumSet.of(ParamsDiffSnapshot.Flags.REMOVED_VAR_GRAVE)); - } - TransformParameters asParameterTransformer(boolean withOffset, Set flags); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/InjectionPointMatcher.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/InjectionPointMatcher.java deleted file mode 100644 index f1b71954..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/InjectionPointMatcher.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.sinytra.adapter.patch.analysis.selector; - -import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; - -import java.util.Optional; -import java.util.function.Predicate; - -public record InjectionPointMatcher(@Nullable String value, TargetMatcher target) { - public InjectionPointMatcher(@Nullable String value, String target) { - this(value, TargetMatcher.create(target)); - } - - public boolean test(String value, String target) { - return (this.value == null || this.value.equals(value)) && this.target.test(target); - } - - interface TargetMatcher extends Predicate { - String target(); - - static TargetMatcher create(String target) { - return Optional.of(target) - .flatMap(str -> MethodQualifier.create(str) - .filter(q -> q.name() != null) - .map(q -> new MethodQualifierMatcher(str, q))) - .orElseGet(() -> new SimpleTargetMatcher(AdapterUtil.maybeRemapFieldRef(target))); - } - } - - private record SimpleTargetMatcher(String target) implements TargetMatcher { - @Override - public boolean test(String s) { - return this.target.equals(s); - } - } - - private record MethodQualifierMatcher(String target, MethodQualifier qualifier) implements TargetMatcher { - @Override - public boolean test(String s) { - return MethodQualifier.create(s).map(this.qualifier::matches).orElse(false); - } - } -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/MethodMatcher.java b/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/MethodMatcher.java deleted file mode 100644 index 62b5716d..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/MethodMatcher.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.sinytra.adapter.patch.analysis.selector; - -import org.jetbrains.annotations.Nullable; - -public class MethodMatcher { - private final String name; - @Nullable - private final String desc; - - public MethodMatcher(String method) { - int descIndex = method.indexOf('('); - this.name = descIndex == -1 ? method : method.substring(0, descIndex); - this.desc = descIndex == -1 ? null : method.substring(descIndex); - } - - public boolean matches(String name, String desc) { - return this.name.equals(name) && (this.desc == null || desc == null || this.desc.equals(desc)); - } -} 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 deleted file mode 100644 index 8cf5a33f..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MethodContext.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.sinytra.adapter.patch.api; - -import com.mojang.datafixers.util.Pair; -import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.ctx.Auditor; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.provider.ClassLookup; - -import java.util.List; - -public interface MethodContext extends Auditor { - ClassNode getMixinClass(); - - MethodNode getMixinMethod(); - - AnnotationHandle methodAnnotation(); - - @Nullable AnnotationHandle injectionPointAnnotation(); - - PatchContext patchContext(); - - TargetPair findCleanInjectionTarget(); - - TargetPair findDirtyInjectionTarget(); - - LocalVariableLookup cleanLocalsTable(); - - LocalVariableLookup dirtyLocalsTable(); - - @Nullable - MethodQualifier getTargetMethodQualifier(); - - List findInjectionTargetInsns(@Nullable TargetPair target); - - /** - * Uncached variant of {@link #findInjectionTargetInsns(TargetPair)} - */ - List computeInjectionTargetInsns(@Nullable TargetPair target); - - @Nullable - Pair> findInjectionTargetCandidates(ClassLookup lookup, boolean ignoreDesc); - - void updateDescription(List parameters); - - boolean isStatic(); - - @Nullable - List getTargetMethodLocals(TargetPair target); - - @Nullable - default List getTargetMethodLocals(TargetPair target, int startPos) { - return getTargetMethodLocals(target, startPos, patchContext().environment().fabricLVTCompatibility()); - } - - @Nullable - List getTargetMethodLocals(TargetPair target, int startPos, int lvtCompatLevel); - - List getLvtCompatLevelsOrdered(); - - boolean failsDirtyInjectionCheck(); - - boolean isNotRequired(); - - boolean hasValidSlice(TargetPair target); -} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java b/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java deleted file mode 100644 index e1eaa9ce..00000000 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParameterTransformer.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.sinytra.adapter.patch.transformer.operation.param; - -import org.objectweb.asm.Type; -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.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; - -import java.util.List; - -public interface ParameterTransformer { - PatchResult apply(final ClassNode classNode, final MethodNode methodNode, final MethodContext methodContext, final PatchContext context, final List parameters, final int offset); -} 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 5c3b305a..c992659d 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,13 +11,16 @@ import org.objectweb.asm.tree.analysis.SourceValue; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.MethodHelper; +import org.sinytra.adapter.next.env.ctx.PatchEnvironment; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.env.util.MixinAnnotations; +import org.sinytra.adapter.next.env.util.TypeConstants; +import org.sinytra.adapter.next.pipeline.Recipe; 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; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import org.sinytra.adapter.patch.api.TargetPair; import org.slf4j.Logger; import org.slf4j.Marker; import org.slf4j.MarkerFactory; @@ -156,7 +159,7 @@ public static VarInsnNode loadType(Type type, int index) { } public static boolean isShadowField(FieldNode field) { - return AdapterUtil.hasAnnotation(field.visibleAnnotations, MixinConstants.SHADOW); + return AdapterUtil.hasAnnotation(field.visibleAnnotations, MixinAnnotations.SHADOW); } public static boolean hasAnnotation(List annotations, String desc) { @@ -195,35 +198,41 @@ public static List getAnnotatedParameters(MethodNode methodNode, Type[] p } @Nullable - public static CapturedLocals getCapturedLocals(MethodNode methodNode, MethodContext methodContext) { - AnnotationHandle annotation = methodContext.methodAnnotation(); + public static CapturedLocals getCapturedLocals(MixinContext context, Recipe recipe) { + TargetPair target = recipe.getDirtyTarget(); + if (target == null) return null; + + return getCapturedLocals(context, target); + } + + // TODO Better way? + @Nullable + public static CapturedLocals getCapturedLocals(MixinContext context, TargetPair dirtyTarget) { + MethodNode methodNode = context.methodNode(); Type[] params = Type.getArgumentTypes(methodNode.desc); OptionalInt paramLocalPos = getCapturedLocalStartingIndex(params); // Sanity check to make sure the injector method takes in a CI or CIR argument if (paramLocalPos.isEmpty()) { - LOGGER.debug("Missing CI or CIR argument in injector of type {}", annotation.getDesc()); - return null; - } - TargetPair target = methodContext.findDirtyInjectionTarget(); - if (target == null) { + LOGGER.debug("Missing CI or CIR argument in injector of type {}", context.methodAnnotation().getDesc()); return null; } - List ignored = getAnnotatedParameters(methodNode, params, MixinConstants.SHARE, (node, type) -> type); + + List ignored = getAnnotatedParameters(methodNode, params, MixinAnnotations.SHARE, (node, type) -> type); Type[] availableParams = Stream.of(params).filter(t -> !ignored.contains(t)).toArray(Type[]::new); - boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0; + boolean isStatic = MethodHelper.isStatic(methodNode); int lvtOffset = isStatic ? 0 : 1; // The first local var in the method's params comes after the target's params plus the CI/CIR parameter int paramLocalPosVal = paramLocalPos.getAsInt(); // Get expected local variables from method parameters List expected = AdapterUtil.summariseLocals(availableParams, paramLocalPosVal); - return new CapturedLocals(target, isStatic, paramLocalPosVal, paramLocalPosVal + expected.size(), lvtOffset, expected, new LocalVariableLookup(methodNode)); + return new CapturedLocals(dirtyTarget, isStatic, paramLocalPosVal, paramLocalPosVal + expected.size(), lvtOffset, expected, new LocalVariableLookup(methodNode)); } private static OptionalInt getCapturedLocalStartingIndex(Type[] params) { for (int i = 0; i < params.length; i++) { Type param = params[i]; - if ((param.equals(MixinConstants.CI_TYPE) || param.equals(MixinConstants.CIR_TYPE)) && i + 1 < params.length) { + if ((param.equals(TypeConstants.CI_TYPE) || param.equals(TypeConstants.CIR_TYPE)) && i + 1 < params.length) { return OptionalInt.of(i + 1); } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodQualifier.java b/definition/src/main/java/org/sinytra/adapter/patch/util/MethodQualifier.java index 2362130d..63b3c1e4 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodQualifier.java +++ b/definition/src/main/java/org/sinytra/adapter/patch/util/MethodQualifier.java @@ -18,7 +18,7 @@ public MethodQualifier(@Nullable String name, @Nullable String desc) { } @Nullable - public static Optional create(String qualifier) { + public static Optional parse(String qualifier) { Matcher matcher = METHOD_QUALIFIER_PATTERN.matcher(qualifier); if (matcher.matches()) { String name = matcher.group("name"); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java index 3fbbb8a4..e6880820 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java @@ -6,7 +6,7 @@ public final class ConfigurationTemplates { public static final PropertyContainerTemplate MIXIN_BASE = PropertyContainerTemplate.builder() .require(Keys.MIXIN_TYPE, Keys.TARGET_CLASS, Keys.TARGET_METHOD, Keys.PARAMETERS, Keys.RETURN_TYPE) - .keys(Keys.LOCALS) + .keys(Keys.LOCALS, Keys.REQUIRE) .build(); public static final PropertyContainerTemplate MIXIN_AT = MIXIN_BASE.extend() .require(Keys.TARGET_AT) diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java b/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java index b367f9aa..9e98b497 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java @@ -5,42 +5,43 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ctx.MethodHelper; -import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.next.env.ctx.*; import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.next.types.TypeAdapter; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.provider.ClassLookup; import java.util.List; -public class MixinContext implements RefMapper { - private final String mixinId; +public class MixinContext implements RefMapper, Auditor { + private final PatchContext patchContext; private final ClassTarget classTarget; private final ClassNode classNode; private final MethodNode methodNode; private final MethodNode originalMethodNode; + + private final AnnotationHandle methodAnnotation; + private final AnnotationHandle injectionPointAnnotation; + private final String mixinId; private final MethodHelper methodHelper; - private final MethodContext methodContext; - private final Resolvers resolvers = new Resolvers(); private final Processors processors = new Processors(); - public MixinContext(ClassTarget classTarget, ClassNode classNode, MethodNode methodNode, MethodContext methodContext) { - this.mixinId = classNode.name + "#" + methodNode.name + methodNode.desc; - + public MixinContext(PatchContext patchContext, ClassTarget classTarget, ClassNode classNode, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation) { + this.patchContext = patchContext; this.classTarget = classTarget; this.classNode = classNode; this.methodNode = methodNode; + this.methodAnnotation = methodAnnotation; + this.injectionPointAnnotation = injectionPointAnnotation; + this.methodHelper = new MethodHelper(this, classTarget.getTypes()); - this.methodContext = methodContext; this.originalMethodNode = AdapterUtil.copyMethod(this.methodNode); + + this.mixinId = classNode.name + "#" + methodNode.name + methodNode.desc; } public String getMixinId() { @@ -77,25 +78,25 @@ public MethodHelper methods() { } public ClassLookup cleanLookup() { - return this.methodContext.patchContext().environment().cleanClassLookup(); + return this.patchContext.environment().cleanClassLookup(); } public ClassLookup dirtyLookup() { - return this.methodContext.patchContext().environment().dirtyClassLookup(); + return this.patchContext.environment().dirtyClassLookup(); } public AnnotationHandle methodAnnotation() { - return this.methodContext.methodAnnotation(); + return this.methodAnnotation; } @Nullable public AnnotationHandle injectionPointAnnotation() { - return this.methodContext.injectionPointAnnotation(); + return this.injectionPointAnnotation; } @Nullable public TypeAdapter getTypeAdapter(Type from, Type to) { - return this.methodContext.patchContext().environment().bytecodeFixerUpper().getTypeAdapter(from, to); + return this.patchContext.environment().bytecodeFixerUpper().getTypeAdapter(from, to); } @Override @@ -104,18 +105,13 @@ public String remap(String refmapEntry) { } public PatchContext patchContext() { - return this.methodContext.patchContext(); + return this.patchContext; } public boolean isStatic() { return MethodHelper.isStatic(this.methodNode); } - @Deprecated - public MethodContext legacy() { - return this.methodContext; - } - public List targetTypes() { return this.classTarget.getTypes(); } @@ -123,4 +119,9 @@ public List targetTypes() { public PatchEnvironment environment() { return patchContext().environment(); } + + @Override + public void recordAudit(Object transform, String message, Object... args) { + environment().auditTrail().recordAudit(transform, this, message, args); + } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/MockMixinRuntime.java b/definition/src/next/java/org/sinytra/adapter/next/env/MockMixinRuntime.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/util/MockMixinRuntime.java rename to definition/src/next/java/org/sinytra/adapter/next/env/MockMixinRuntime.java index 7e9a1c7d..1adebedb 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/MockMixinRuntime.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/MockMixinRuntime.java @@ -1,8 +1,8 @@ -package org.sinytra.adapter.patch.util; +package org.sinytra.adapter.next.env; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.PatchEnvironment; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.extensibility.IMixinConfig; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java index 6f8ed4bd..792eef49 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java @@ -4,12 +4,12 @@ import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.config.MutablePropertyContainer; import org.sinytra.adapter.next.pipeline.config.PropertyContainer; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.pipeline.config.PropertyKey; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.MixinConstants; import org.sinytra.adapter.patch.util.MethodQualifier; import org.spongepowered.asm.mixin.injection.At; @@ -57,7 +57,7 @@ public void apply(AnnotationHandle handle) { } public AnnotationNode toAnnotationNode() { - AnnotationNode node = new AnnotationNode(MixinConstants.AT); + AnnotationNode node = new AnnotationNode(MixinAnnotations.AT); this.properties.getProperties().forEach((key, value) -> node.visit(key.name(), value)); return node; } @@ -97,7 +97,7 @@ public int hashCode() { } public static Optional parse(AnnotationHandle annotation, RefMapper mapper) { - PropertyContainer container = MutablePropertyContainer.parse(annotation, TEMPLATE, mapper); + PropertyContainer container = MutablePropertyContainer.parseValid(annotation, TEMPLATE, mapper); return Optional.ofNullable(container).map(AtData::new); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java index f5c1f6eb..1244758c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java @@ -8,8 +8,8 @@ import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.MIXIN_TARGETS; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.MIXIN_VALUE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.MIXIN_TARGETS; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.MIXIN_VALUE; public class ClassTarget { private final AnnotationHandle handle; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java b/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java index 32644cbb..f53c2998 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java @@ -4,11 +4,11 @@ import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.tree.AnnotationNode; import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.MixinConstants; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.SLICE_FROM; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.SLICE_TO; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.SLICE_FROM; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.SLICE_TO; public class SliceData { @Nullable @@ -42,13 +42,13 @@ public static SliceData parse(AnnotationHandle handle, RefMapper context) { } public AnnotationNode toAnnotationNode() { - AnnotationNode slice = new AnnotationNode(MixinConstants.SLICE); + AnnotationNode slice = new AnnotationNode(MixinAnnotations.SLICE); if (this.from != null) { - AnnotationVisitor fromNode = slice.visitAnnotation(SLICE_FROM, MixinConstants.AT); + AnnotationVisitor fromNode = slice.visitAnnotation(SLICE_FROM, MixinAnnotations.AT); this.from.toAnnotationNode().accept(fromNode); } if (this.to != null) { - AnnotationVisitor fromNode = slice.visitAnnotation(SLICE_TO, MixinConstants.AT); + AnnotationVisitor fromNode = slice.visitAnnotation(SLICE_TO, MixinAnnotations.AT); this.to.toAnnotationNode().accept(fromNode); } return slice; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchAuditTrail.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrail.java similarity index 67% rename from definition/src/main/java/org/sinytra/adapter/patch/api/PatchAuditTrail.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrail.java index 21a33ada..56e7bf11 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchAuditTrail.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrail.java @@ -1,28 +1,29 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; import it.unimi.dsi.fastutil.Pair; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.PatchAuditTrailImpl; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.config.Configuration; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; -public interface PatchAuditTrail { - static PatchAuditTrail create() { - return new PatchAuditTrailImpl(); +public interface AuditTrail { + static AuditTrail create() { + return new AuditTrailImpl(); } - void prepareMethod(MethodContext methodContext); + void prepareMethod(MixinContext context); void recordAudit(Object transform, ClassNode classNode, String message, Object... args); - void recordAudit(Object transform, MethodContext methodContext, String message, Object... args); + void recordAudit(Object transform, MixinContext context, String message, Object... args); - void recordResult(MethodContext methodContext, Match match); + void recordResult(MixinContext context, Configuration configuration, Match match); String getCompleteReport(); @@ -35,9 +36,9 @@ static PatchAuditTrail create() { Map getCandidates(); @Nullable - Match getMatch(MethodContext methodContext); + Match getMatch(MixinContext context); - void merge(PatchAuditTrail other); + void merge(AuditTrail other); void silenceClasses(Set classes); @@ -76,8 +77,8 @@ public Match or(Match other) { record Candidate(ClassNode classNode, MethodNode methodNode) {} record AuditLog(@Nullable String originalMethod, List> entries) { - public static AuditLog create(MethodContext methodContext) { - return new AuditLog(methodContext.getMixinMethod().name + methodContext.getMixinMethod().desc, new ArrayList<>()); + public static AuditLog create(MixinContext context) { + return new AuditLog(context.methodNode().name + context.methodNode().desc, new ArrayList<>()); } } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrailImpl.java similarity index 81% rename from definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrailImpl.java index 4dbc97e4..eb04a170 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/PatchAuditTrailImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrailImpl.java @@ -1,12 +1,13 @@ -package org.sinytra.adapter.patch; +package org.sinytra.adapter.next.env.ctx; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.Pair; import org.jetbrains.annotations.Nullable; 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.PatchAuditTrail; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.slf4j.Logger; import java.text.DecimalFormat; @@ -15,16 +16,16 @@ import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; -public class PatchAuditTrailImpl implements PatchAuditTrail { +public class AuditTrailImpl implements AuditTrail { private static final DecimalFormat FORMAT = new DecimalFormat("##.00"); private static final Logger LOGGER = LogUtils.getLogger(); private final Map auditTrail = new LinkedHashMap<>(); private final Map candidates = new ConcurrentHashMap<>(); - public void prepareMethod(MethodContext methodContext) { - Candidate candidate = new Candidate(methodContext.getMixinClass(), methodContext.getMixinMethod()); + public void prepareMethod(MixinContext context) { + Candidate candidate = new Candidate(context.classNode(), context.methodNode()); synchronized (this.auditTrail) { - this.auditTrail.put(candidate, AuditLog.create(methodContext)); + this.auditTrail.put(candidate, AuditLog.create(context)); } } @@ -33,9 +34,9 @@ public void recordAudit(Object transform, ClassNode classNode, String message, O recordAudit(transform, null, candidate, message.formatted(args)); } - public void recordAudit(Object transform, MethodContext methodContext, String message, Object... args) { - Candidate candidate = new Candidate(methodContext.getMixinClass(), methodContext.getMixinMethod()); - recordAudit(transform, methodContext.getMixinMethod(), candidate, message.formatted(args)); + public void recordAudit(Object transform, MixinContext context, String message, Object... args) { + Candidate candidate = new Candidate(context.classNode(), context.methodNode()); + recordAudit(transform, context.methodNode(), candidate, message.formatted(args)); } private void recordAudit(Object transform, @Nullable MethodNode methodNode, Candidate candidate, String message) { @@ -56,10 +57,13 @@ private void recordAudit(Object transform, @Nullable MethodNode methodNode, Cand } } - public void recordResult(MethodContext methodContext, Match match) { - Candidate candidate = new Candidate(methodContext.getMixinClass(), methodContext.getMixinMethod()); + public void recordResult(MixinContext context, Configuration configuration, Match match) { + Candidate candidate = new Candidate(context.classNode(), context.methodNode()); this.candidates.compute(candidate, (key, prev) -> { - Match maybeIgnore = match == Match.NONE && methodContext.isNotRequired() ? Match.IGNORED : match; + boolean isNotRequired = configuration.getProperty(Keys.REQUIRE) + .map(i -> i == 0) + .orElse(false); + Match maybeIgnore = match == Match.NONE && isNotRequired ? Match.IGNORED : match; return prev == null ? maybeIgnore : prev.or(maybeIgnore); }); } @@ -126,13 +130,13 @@ public Map getCandidates() { @Nullable @Override - public Match getMatch(MethodContext methodContext) { - Candidate candidate = new Candidate(methodContext.getMixinClass(), methodContext.getMixinMethod()); + public Match getMatch(MixinContext context) { + Candidate candidate = new Candidate(context.classNode(), context.methodNode()); return this.candidates.get(candidate); } @Override - public void merge(PatchAuditTrail other) { + public void merge(AuditTrail other) { synchronized (this.auditTrail) { this.auditTrail.putAll(other.getAuditTrail()); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/LocalVariable.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/LocalVariable.java similarity index 67% rename from definition/src/main/java/org/sinytra/adapter/patch/api/LocalVariable.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/LocalVariable.java index 9cb159c3..e9e0e3b4 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/LocalVariable.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/LocalVariable.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; import org.objectweb.asm.Type; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java index 1892a17c..efd1d7e7 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java @@ -8,7 +8,6 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.slf4j.Logger; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java index 50115cef..25456799 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java @@ -13,10 +13,9 @@ import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.MockMixinRuntime; +import org.sinytra.adapter.next.env.MockMixinRuntime; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.slf4j.Logger; import org.spongepowered.asm.mixin.injection.InjectionPoint; @@ -24,13 +23,15 @@ import org.spongepowered.asm.mixin.injection.code.MethodSlice; import org.spongepowered.asm.mixin.injection.struct.Target; import org.spongepowered.asm.mixin.refmap.IMixinContext; +import org.spongepowered.asm.util.Locals; import java.util.*; import java.util.function.BiFunction; import java.util.function.Supplier; +import java.util.stream.Stream; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.*; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.*; public class MethodHelper { private static final Logger LOGGER = LogUtils.getLogger(); @@ -149,7 +150,7 @@ public List resolveCapturedMethodParams(Configuration clean, Configuration } @Nullable - private List computeInjectionTargetInsns(@Nullable TargetPair target, Supplier atNodeSupplier, BiFunction injectionPointParser, boolean ignoreShift) { + public List computeInjectionTargetInsns(@Nullable TargetPair target, Supplier atNodeSupplier, BiFunction injectionPointParser, boolean ignoreShift) { if (target == null) { return List.of(); } @@ -202,6 +203,41 @@ private InsnList computeSlicedInsns(ISliceContext context, AnnotationNode annota return slice.getSlice(mixinTarget); } + @Nullable + public List getTargetMethodLocals(TargetPair target) { + Type[] targetParams = Type.getArgumentTypes(target.methodNode().desc); + boolean isStatic = isStatic(this.context.methodNode()); + int lvtOffset = isStatic ? 0 : 1; + // The starting LVT index is of the first var after all method parameters. Offset by 1 for instance methods to skip 'this' + int targetLocalPos = targetParams.length + lvtOffset; + return getTargetMethodLocals(target, targetLocalPos); + } + + @Nullable + public List getTargetMethodLocals(TargetPair target, int startPos) { + return getTargetMethodLocals(target, startPos, this.context.environment().fabricLVTCompatibility()); + } + + @Nullable + public List getTargetMethodLocals(TargetPair target, int startPos, int lvtCompatLevel) { + List targetInsns = findInjectionTargetInsns(target); + if (targetInsns.isEmpty()) { + LOGGER.debug("Skipping LVT patch, no target instructions found"); + return null; + } + // Get available local variables at the injection point in the target method + LocalVariableNode[] localVariables; + // Synchronize to avoid issues in mixin. This is necessary. + synchronized (this) { + localVariables = Locals.getLocalsAt(target.classNode(), target.methodNode(), targetInsns.getFirst(), lvtCompatLevel); + } + LocalVariable[] locals = Stream.of(localVariables) + .filter(Objects::nonNull) + .map(lv -> new LocalVariable(lv.index, Type.getType(lv.desc))) + .toArray(LocalVariable[]::new); + return AdapterUtil.summariseLocals(locals, startPos); + } + public static boolean isStatic(MethodNode node) { return (node.access & Opcodes.ACC_STATIC) != 0; } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinClassGenerator.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGenerator.java similarity index 90% rename from definition/src/main/java/org/sinytra/adapter/patch/api/MixinClassGenerator.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGenerator.java index ebcb7c19..5fb4af87 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinClassGenerator.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGenerator.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/MixinClassGeneratorImpl.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGeneratorImpl.java similarity index 91% rename from definition/src/main/java/org/sinytra/adapter/patch/MixinClassGeneratorImpl.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGeneratorImpl.java index 2640e5cc..0a10b2f2 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/MixinClassGeneratorImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGeneratorImpl.java @@ -1,12 +1,11 @@ -package org.sinytra.adapter.patch; +package org.sinytra.adapter.next.env.ctx; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.api.MixinClassGenerator; -import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.spongepowered.asm.service.MixinService; import java.io.IOException; @@ -49,7 +48,7 @@ private ClassNode doGenerateMixinClass(String className, String targetClass, @Nu boolean itf = (targetNode.access & Opcodes.ACC_INTERFACE) == Opcodes.ACC_INTERFACE; int flags = itf ? Opcodes.ACC_INTERFACE : Opcodes.ACC_FINAL; node.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT | flags, className, null, parent != null ? parent : "java/lang/Object", null); - AnnotationVisitor mixinAnn = node.visitAnnotation(MixinConstants.MIXIN, false); + AnnotationVisitor mixinAnn = node.visitAnnotation(MixinAnnotations.MIXIN, false); { AnnotationVisitor valueArray = mixinAnn.visitArray("value"); valueArray.visit(null, Type.getType(Type.getObjectType(targetClass).getDescriptor())); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchContext.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContext.java similarity index 84% rename from definition/src/main/java/org/sinytra/adapter/patch/api/PatchContext.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContext.java index 87681f07..ed062ede 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchContext.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContext.java @@ -1,8 +1,7 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.PatchContextImpl; import java.util.List; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/PatchContextImpl.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContextImpl.java similarity index 89% rename from definition/src/main/java/org/sinytra/adapter/patch/PatchContextImpl.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContextImpl.java index 77b5a65b..bdd5baa7 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/PatchContextImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContextImpl.java @@ -1,9 +1,7 @@ -package org.sinytra.adapter.patch; +package org.sinytra.adapter.next.env.ctx; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchEnvironment; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchEnvironment.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironment.java similarity index 81% rename from definition/src/main/java/org/sinytra/adapter/patch/api/PatchEnvironment.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironment.java index a4675c89..241c87dd 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchEnvironment.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironment.java @@ -1,13 +1,12 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.PatchEnvironmentImpl; import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; +import org.sinytra.adapter.next.types.BytecodeFixerUpper; import org.sinytra.adapter.patch.util.provider.ClassLookup; public interface PatchEnvironment { - static PatchEnvironment create(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility, PatchAuditTrail auditTrail) { + static PatchEnvironment create(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility, AuditTrail auditTrail) { return new PatchEnvironmentImpl(refmapHolder, cleanClassLookup, bytecodeFixerUpper, fabricLVTCompatibility, auditTrail); } @@ -30,5 +29,5 @@ static PatchEnvironment create(RefmapHolder refmapHolder, ClassLookup cleanClass int fabricLVTCompatibility(); - PatchAuditTrail auditTrail(); + AuditTrail auditTrail(); } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/PatchEnvironmentImpl.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironmentImpl.java similarity index 75% rename from definition/src/main/java/org/sinytra/adapter/patch/PatchEnvironmentImpl.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironmentImpl.java index 15d2e412..e899dd23 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/PatchEnvironmentImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironmentImpl.java @@ -1,12 +1,8 @@ -package org.sinytra.adapter.patch; +package org.sinytra.adapter.next.env.ctx; import org.jetbrains.annotations.Nullable; import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.patch.api.MixinClassGenerator; -import org.sinytra.adapter.patch.api.PatchAuditTrail; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import org.sinytra.adapter.patch.api.RefmapHolder; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; +import org.sinytra.adapter.next.types.BytecodeFixerUpper; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.sinytra.adapter.patch.util.provider.MixinClassLookup; @@ -17,14 +13,14 @@ public record PatchEnvironmentImpl( MixinClassGenerator classGenerator, InheritanceHandler inheritanceHandler, int fabricLVTCompatibility, - PatchAuditTrail auditTrail + AuditTrail auditTrail ) implements PatchEnvironment { - public PatchEnvironmentImpl(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility, PatchAuditTrail auditTrail) { + public PatchEnvironmentImpl(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility, AuditTrail auditTrail) { this(refmapHolder, cleanClassLookup, MixinClassLookup.INSTANCE, bytecodeFixerUpper, new MixinClassGeneratorImpl(), new InheritanceHandler(MixinClassLookup.INSTANCE), fabricLVTCompatibility, auditTrail); } public PatchEnvironmentImpl(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, ClassLookup dirtyClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility) { - this(refmapHolder, cleanClassLookup, dirtyClassLookup, bytecodeFixerUpper, new MixinClassGeneratorImpl(), new InheritanceHandler(MixinClassLookup.INSTANCE), fabricLVTCompatibility, new PatchAuditTrailImpl()); + this(refmapHolder, cleanClassLookup, dirtyClassLookup, bytecodeFixerUpper, new MixinClassGeneratorImpl(), new InheritanceHandler(MixinClassLookup.INSTANCE), fabricLVTCompatibility, new AuditTrailImpl()); } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchResult.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchResult.java similarity index 88% rename from definition/src/main/java/org/sinytra/adapter/patch/api/PatchResult.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchResult.java index b98e90e2..3f328d9f 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/PatchResult.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchResult.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; public enum PatchResult { PASS, diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/RefmapHolder.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefmapHolder.java similarity index 75% rename from definition/src/main/java/org/sinytra/adapter/patch/api/RefmapHolder.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefmapHolder.java index 74162df2..6281202b 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/RefmapHolder.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefmapHolder.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; public interface RefmapHolder { String remap(String cls, String reference); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/TargetPair.java b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/TargetPair.java similarity index 79% rename from definition/src/main/java/org/sinytra/adapter/patch/api/TargetPair.java rename to definition/src/next/java/org/sinytra/adapter/next/env/ctx/TargetPair.java index 80e4672a..7f84ed17 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/TargetPair.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/ctx/TargetPair.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.ctx; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java index 2389456e..16b32383 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java @@ -3,7 +3,7 @@ import com.google.common.collect.ImmutableMap; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.next.env.util.TypeConstants; import java.util.*; import java.util.function.Predicate; @@ -20,8 +20,8 @@ public record ParamGroup(ParamGroupType type, String name, Predicate public static final ParamGroup CAPTURED_PARAMS = new ParamGroup(ParamGroupType.VARIABLE, "captured_params", i -> !i.isLocal()); public static final ParamGroup SINGLE_ANY = new ParamGroup(ParamGroupType.SINGLE, "single_any", i -> true); - public static final ParamGroup CI_CIR = new ParamGroup(ParamGroupType.SINGLE, "ci_cir", i -> i.getType().equals(MixinConstants.CI_TYPE) || i.getType().equals(MixinConstants.CIR_TYPE)); - public static final ParamGroup OPERATION = new ParamGroup(ParamGroupType.SINGLE, "operation", i -> i.getType().equals(MixinConstants.OPERATION_TYPE)); + public static final ParamGroup CI_CIR = new ParamGroup(ParamGroupType.SINGLE, "ci_cir", i -> i.getType().equals(TypeConstants.CI_TYPE) || i.getType().equals(TypeConstants.CIR_TYPE)); + public static final ParamGroup OPERATION = new ParamGroup(ParamGroupType.SINGLE, "operation", i -> i.getType().equals(TypeConstants.OPERATION_TYPE)); public static final ParamGroup LOCALS = new ParamGroup(ParamGroupType.VARIABLE, "locals", Parameter::isLocal); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java index e46645d0..8bd60585 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java @@ -2,7 +2,7 @@ import com.google.common.collect.ImmutableList; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import java.util.ArrayList; import java.util.List; @@ -26,7 +26,7 @@ public List getAnnotations() { } public boolean isLocal() { - return hasAnnotation(MixinConstants.LOCAL); + return hasAnnotation(MixinAnnotations.LOCAL); } public boolean hasAnnotation(String desc) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java b/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotationConstants.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java rename to definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotationConstants.java index 7da76f08..e1c3f342 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/MixinAnnotationConstants.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotationConstants.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ann; +package org.sinytra.adapter.next.env.util; public class MixinAnnotationConstants { public static final String MIXIN_VALUE = "value"; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java b/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotations.java similarity index 73% rename from definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java rename to definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotations.java index 745077e7..ed59a6d7 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/api/MixinConstants.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotations.java @@ -1,11 +1,6 @@ -package org.sinytra.adapter.patch.api; +package org.sinytra.adapter.next.env.util; -import org.objectweb.asm.Type; -import org.spongepowered.asm.mixin.FabricUtil; - -import java.util.List; - -public class MixinConstants { +public class MixinAnnotations { // Standard mixins public static final String INJECT = "Lorg/spongepowered/asm/mixin/injection/Inject;"; public static final String REDIRECT = "Lorg/spongepowered/asm/mixin/injection/Redirect;"; @@ -24,8 +19,6 @@ public class MixinConstants { public static final String WRAP_OPERATION = "Lcom/llamalad7/mixinextras/injector/wrapoperation/WrapOperation;"; public static final String WRAP_OPERATION_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/wrapoperation/WrapOperation"; public static final String WRAP_WITH_CONDITION = "Lcom/llamalad7/mixinextras/injector/WrapWithCondition;"; - public static final String OPERATION_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/wrapoperation/Operation"; - public static final Type OPERATION_TYPE = Type.getObjectType(OPERATION_INTERNAL_NAME); public static final String LOCAL = "Lcom/llamalad7/mixinextras/sugar/Local;"; public static final String SHARE = "Lcom/llamalad7/mixinextras/sugar/Share;"; // Adapter custom mixin injectors @@ -38,12 +31,4 @@ public class MixinConstants { public static final String COERCE = "Lorg/spongepowered/asm/mixin/injection/Coerce;"; public static final String CONSTANT = "Lorg/spongepowered/asm/mixin/injection/Constant;"; public static final String SLICE = "Lorg/spongepowered/asm/mixin/injection/Slice;"; - public static final List LVT_COMPATIBILITY_LEVELS = List.of(FabricUtil.COMPATIBILITY_0_10_0, FabricUtil.COMPATIBILITY_0_9_2); - - public static final String DEPRECATED = "Ljava/lang/Deprecated;"; - - // Types - public static final Type CI_TYPE = Type.getObjectType("org/spongepowered/asm/mixin/injection/callback/CallbackInfo"); - public static final Type CIR_TYPE = Type.getObjectType("org/spongepowered/asm/mixin/injection/callback/CallbackInfoReturnable"); - public static final Type OBJECT_TYPE = Type.getType(Object.class); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/OrderedRegistry.java b/definition/src/next/java/org/sinytra/adapter/next/env/util/OrderedRegistry.java similarity index 98% rename from definition/src/next/java/org/sinytra/adapter/next/env/OrderedRegistry.java rename to definition/src/next/java/org/sinytra/adapter/next/env/util/OrderedRegistry.java index 4bdacc8e..0f477515 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/OrderedRegistry.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/util/OrderedRegistry.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env; +package org.sinytra.adapter.next.env.util; import org.jetbrains.annotations.Nullable; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/util/TypeConstants.java b/definition/src/next/java/org/sinytra/adapter/next/env/util/TypeConstants.java new file mode 100644 index 00000000..eee85cce --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/env/util/TypeConstants.java @@ -0,0 +1,16 @@ +package org.sinytra.adapter.next.env.util; + +import org.objectweb.asm.Type; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +public class TypeConstants { + public static final String OPERATION_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/wrapoperation/Operation"; + public static final Type OPERATION_TYPE = Type.getObjectType(OPERATION_INTERNAL_NAME); + + public static final Type CI_TYPE = Type.getType(CallbackInfo.class); + public static final Type CIR_TYPE = Type.getType(CallbackInfoReturnable.class); + + public static final Type OBJECT_TYPE = Type.getType(Object.class); + public static final String DEPRECATED = Type.getType(Deprecated.class).getDescriptor(); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/WeighedDisambiguation.java b/definition/src/next/java/org/sinytra/adapter/next/env/util/WeighedDisambiguation.java similarity index 97% rename from definition/src/next/java/org/sinytra/adapter/next/env/WeighedDisambiguation.java rename to definition/src/next/java/org/sinytra/adapter/next/env/util/WeighedDisambiguation.java index 9cacefaa..ab5ea813 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/WeighedDisambiguation.java +++ b/definition/src/next/java/org/sinytra/adapter/next/env/util/WeighedDisambiguation.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env; +package org.sinytra.adapter.next.env.util; import org.jetbrains.annotations.Nullable; import org.sinytra.adapter.patch.util.AdapterUtil; diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java b/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java index 18b605fa..b19d6b11 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java +++ b/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java @@ -1,16 +1,15 @@ package org.sinytra.adapter.next.flow; import org.sinytra.adapter.next.pipeline.PipelineMethodTransformer; -import org.sinytra.adapter.next.transform.FieldAccessorTypeTransformer; +import org.sinytra.adapter.next.types.FieldAccessorTypeTransformer; import org.sinytra.adapter.next.transform.MethodTransformer; import org.sinytra.adapter.next.transform.cls.DynamicAnonClassIndexPatch; import org.sinytra.adapter.next.transform.cls.DynamicAnonymousShadowFieldTypePatch; import org.sinytra.adapter.next.transform.patch.MethodPatch; import org.sinytra.adapter.next.transform.patch.MethodPatchTransformer; -import org.sinytra.adapter.next.transform.preprocess.CapturedLocalsPreProcessor; import org.sinytra.adapter.next.transform.preprocess.LocalCaptureUpgradeTransformer; import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.patch.fixes.FieldTypeUsageTransformer; +import org.sinytra.adapter.next.types.FieldTypeUsageTransformer; import java.util.List; @@ -25,7 +24,6 @@ public static List methodTransformers(List patch return List.of( new FieldAccessorTypeTransformer(), // Interface mixin only new LocalCaptureUpgradeTransformer(), - new CapturedLocalsPreProcessor(), new MethodPatchTransformer(patches), new PipelineMethodTransformer() ); diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java b/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java index 2a898081..4edffb9d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java +++ b/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java @@ -8,17 +8,15 @@ import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.next.env.ctx.MethodHelper; import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.config.*; -import org.sinytra.adapter.next.type.MixinType; -import org.sinytra.adapter.next.type.MixinTypes; +import org.sinytra.adapter.next.mixin.MixinType; +import org.sinytra.adapter.next.mixin.MixinTypes; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchEnvironment; +import org.sinytra.adapter.next.env.ctx.PatchEnvironment; import java.util.ArrayList; import java.util.List; -import java.util.Set; public class MixinParser { @@ -39,7 +37,6 @@ public static MixinClassHandle parseMixins(ClassNode classNode, PatchEnvironment return new MixinClassHandle(cls, methods); } - @SuppressWarnings({"rawtypes", "unchecked"}) private static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, RefMapper mapper) { if (method.visibleAnnotations == null) return null; @@ -51,28 +48,11 @@ private static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, if (mixinType == null) continue; PropertyContainerTemplate template = mixinType.getConfigurationTemplate(); - Set> keys = template.getKeys(); - MutablePropertyContainer properties = MutablePropertyContainer.create(template); + MutablePropertyContainer properties = MutablePropertyContainer.parse(handle, template, mapper); properties.setProperty(Keys.MIXIN_TYPE, annotation.desc); properties.setProperty(Keys.TARGET_CLASS, cls.getSingle().getInternalName()); properties.setProperty(Keys.RETURN_TYPE, Type.getReturnType(method.desc)); - - for (PropertyKey key : keys) { - if (properties.hasProperty(key)) continue; - - Object value = handle.getValue(key.name()).map(AnnotationValueHandle::get).orElse(null); - if (value == null) continue; - - if (key.parser() != null) { - Object parsed = key.parser().parse(value, mapper); - properties.setProperty(key, parsed); - } else { - throw new IllegalStateException("Cannot parse for key %s, it does not define a parser".formatted(key.name())); - } - } - - // Set static property properties.setProperty(SpecialKeys.STATIC, MethodHelper.isStatic(method)); return new MixinMethodHandle(mixinType, method, handle, properties); @@ -86,7 +66,7 @@ private static ClassTarget parseTargetClass(ClassNode classNode) { if (classNode.invisibleAnnotations == null) return null; for (AnnotationNode annotation : classNode.invisibleAnnotations) { - if (annotation.desc.equals(MixinConstants.MIXIN)) { + if (annotation.desc.equals(MixinAnnotations.MIXIN)) { AnnotationHandle ann = new AnnotationHandle(annotation); return ClassTarget.parse(ann); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java b/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java index 32cf5b9f..1ae19e53 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java +++ b/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java @@ -4,18 +4,19 @@ import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; +import org.sinytra.adapter.next.env.ctx.PatchContext; +import org.sinytra.adapter.next.env.ctx.PatchContextImpl; +import org.sinytra.adapter.next.env.ctx.PatchEnvironment; +import org.sinytra.adapter.next.env.util.MixinAnnotationConstants; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; import org.sinytra.adapter.next.transform.ClassTransformer; import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.next.type.MixinType; -import org.sinytra.adapter.patch.MethodContextImpl; -import org.sinytra.adapter.patch.PatchContextImpl; +import org.sinytra.adapter.next.mixin.MixinType; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.*; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.MethodQualifier; import org.slf4j.Logger; @@ -73,8 +74,9 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P MethodQualifier target = mixin.properties().getProperty(Keys.TARGET_METHOD).orElse(null); if (target == null) return PatchResult.PASS; + AnnotationHandle atHandle = mixin.methodAnnotation().getNested(MixinAnnotationConstants.PROPERTY_AT).orElse(null); MixinType mixinType = mixin.mixinType(); - MixinContext mixinContext = buildContext(classNode, classTarget, mixin, patchContext); + MixinContext mixinContext = new MixinContext(patchContext, classTarget, classNode, mixin.methodNode(), mixin.methodAnnotation(), atHandle); String mixinId = mixinContext.getMixinId(); // Build base config @@ -97,11 +99,10 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P return PatchResult.PASS; } - MethodContext legacy = mixinContext.legacy(); PatchResult result = PatchResult.PASS; // TODO Audit trail if (!this.methodTransformers.isEmpty()) { - this.environment.auditTrail().prepareMethod(legacy); + this.environment.auditTrail().prepareMethod(mixinContext); } for (MethodTransformer transformer : this.methodTransformers) { @@ -117,21 +118,4 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P return result; } - - private MixinContext buildContext(ClassNode classNode, ClassTarget classTarget, MixinParser.MixinMethodHandle mixin, PatchContext patchContext) { - AnnotationHandle handle = mixin.methodAnnotation().getNested(MixinAnnotationConstants.PROPERTY_AT) - .orElse(null); - - MethodContext legacyContext = MethodContextImpl.builder() - .classNode(classNode) - .rawClassAnnotation(classTarget.getHandle()) - .classAnnotation(classTarget.getValueHandle()) - .targetTypes(classTarget.getTypes()) - .methodNode(mixin.methodNode()) - .methodAnnotation(mixin.methodAnnotation()) - .injectionPointAnnotation(handle) - .build(patchContext); - - return new MixinContext(classTarget, classNode, mixin.methodNode(), legacyContext); - } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/InjectMixin.java similarity index 99% rename from definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/InjectMixin.java index 08728396..64dfc70a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/InjectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/InjectMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinType.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/MixinType.java index 06f623b3..9f3ddc98 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/MixinType.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinType.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.pipeline.Recipe; diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinTypes.java similarity index 86% rename from definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/MixinTypes.java index ee0e3732..732bbbc8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/MixinTypes.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinTypes.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyVariable; @@ -29,8 +29,8 @@ public class MixinTypes { registerMixinType(ModifyVariable.class, MODIFY_VAR); registerMixinType(ModifyArg.class, MODIFY_ARG); registerMixinType(Redirect.class, REDIRECT); - registerMixinType(MixinConstants.WRAP_OPERATION_INTERNAL_NAME, WRAP_OP); - registerMixinType(MixinConstants.MODIFY_EXPR_VAL_INTERNAL_NAME, MODIFY_EXPR_VAL); + registerMixinType(MixinAnnotations.WRAP_OPERATION_INTERNAL_NAME, WRAP_OP); + registerMixinType(MixinAnnotations.MODIFY_EXPR_VAL_INTERNAL_NAME, MODIFY_EXPR_VAL); } @Nullable diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyArgMixin.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyArgMixin.java index 6d6b25d4..dd02d533 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyArgMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyArgMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; @@ -18,7 +18,7 @@ import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.next.types.TypeAdapter; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; @@ -71,8 +71,8 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo @Nullable private static Type findArgType(MixinContext context, AtData cleanAtData, AtData atData, Configuration dirty) { - MethodQualifier cleanQualifier = cleanAtData.getTarget().flatMap(MethodQualifier::create).orElse(null); - MethodQualifier dirtyQualifier = atData.getTarget().flatMap(MethodQualifier::create).orElse(null); + MethodQualifier cleanQualifier = cleanAtData.getTarget().flatMap(MethodQualifier::parse).orElse(null); + MethodQualifier dirtyQualifier = atData.getTarget().flatMap(MethodQualifier::parse).orElse(null); if (cleanQualifier != null && dirtyQualifier != null) { List cleanArgs = Parameters.getParameterTypes(cleanQualifier.desc()); List dirtyArgs = Parameters.getParameterTypes(dirtyQualifier.desc()); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyExpressionValueMixin.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyExpressionValueMixin.java index 008c396b..30b3b40c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyExpressionValueMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyExpressionValueMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; @@ -18,7 +18,7 @@ import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; @@ -46,7 +46,7 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo return TxResult.FAIL; } - MethodQualifier targetDesc = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); + MethodQualifier targetDesc = dirty.getAtData().getTarget().flatMap(MethodQualifier::parse).orElse(null); if (targetDesc == null) { // Best effort dirty.inheritParameters(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyReturnValueMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyReturnValueMixin.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/type/ModifyReturnValueMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyReturnValueMixin.java index 8632b1ab..46ab3873 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyReturnValueMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyReturnValueMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.pipeline.Recipe; diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyVariableMixin.java similarity index 97% rename from definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyVariableMixin.java index d3ba07e7..640f1453 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/ModifyVariableMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyVariableMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; @@ -19,7 +19,7 @@ import org.sinytra.adapter.next.pipeline.resolver.special.InjectorOrdinalResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ModifyVarAtReturnResolver; import org.sinytra.adapter.next.pipeline.resolver.special.ModifyVarUpgradeResolver; -import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.next.types.TypeAdapter; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/RedirectMixin.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/RedirectMixin.java index e175eee7..d62ff3c5 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/RedirectMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/RedirectMixin.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.objectweb.asm.Type; import org.sinytra.adapter.next.env.ConfigurationTemplates; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; +import org.sinytra.adapter.next.env.util.MixinAnnotationConstants; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; @@ -43,7 +43,7 @@ public TxResult preProcess(MixinContext context, MutableConfiguration clean, Res if (clean.getAtData() == null || !MixinAnnotationConstants.AT_VAL_INVOKE.equals(clean.getAtData().getValue())) return TxResult.FAIL; - MethodQualifier targetDesc = clean.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); + MethodQualifier targetDesc = clean.getAtData().getTarget().flatMap(MethodQualifier::parse).orElse(null); if (targetDesc == null) return TxResult.FAIL; @@ -66,7 +66,7 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo if (dirty.getTargetMethod() == null) return TxResult.FAIL; - MethodQualifier targetDesc = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); + MethodQualifier targetDesc = dirty.getAtData().getTarget().flatMap(MethodQualifier::parse).orElse(null); if (targetDesc == null) return TxResult.FAIL; diff --git a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/WrapOperationMixin.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java rename to definition/src/next/java/org/sinytra/adapter/next/mixin/WrapOperationMixin.java index bf607b00..8f941169 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/type/WrapOperationMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/mixin/WrapOperationMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.type; +package org.sinytra.adapter.next.mixin; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; @@ -20,7 +20,7 @@ import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.ComparingInjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.patch.api.MixinConstants; +import org.sinytra.adapter.next.env.util.TypeConstants; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; @@ -56,7 +56,7 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo if (dirty.getTargetMethod() == null) return TxResult.FAIL; if (dirty.getAtData() == null) return TxResult.PASS; - MethodQualifier dirtyAtTarget = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); + MethodQualifier dirtyAtTarget = dirty.getAtData().getTarget().flatMap(MethodQualifier::parse).orElse(null); if (dirtyAtTarget == null) return TxResult.FAIL; @@ -72,7 +72,7 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo MethodParameters params = MethodParameters.builder() .putTypes(METHOD_PARAMS, callTypes) - .putType(OPERATION, MixinConstants.OPERATION_TYPE) + .putType(OPERATION, TypeConstants.OPERATION_TYPE) .putTypes(CAPTURED_PARAMS, dirtyCaptured) .put(LOCALS, clean.getParameters().get(LOCALS)) .build(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java index 22001914..cbefabe0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java @@ -1,9 +1,15 @@ package org.sinytra.adapter.next.pipeline; import com.mojang.logging.LogUtils; +import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.ann.SliceData; +import org.sinytra.adapter.next.env.ctx.AuditTrail; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; @@ -12,13 +18,14 @@ import org.sinytra.adapter.next.pipeline.resolver.Resolver; import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.next.type.MixinType; -import org.sinytra.adapter.next.type.MixinTypes; -import org.sinytra.adapter.patch.api.PatchAuditTrail; -import org.sinytra.adapter.patch.api.PatchResult; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.mixin.MixinType; +import org.sinytra.adapter.next.mixin.MixinTypes; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.slf4j.Logger; +import org.spongepowered.asm.mixin.injection.InjectionPoint; +import org.spongepowered.asm.mixin.injection.points.BeforeConstant; +import java.util.List; import java.util.Objects; import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; @@ -33,11 +40,11 @@ public PatchResult apply(MixinContext context, Configuration config) { return PatchResult.PASS; TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), config.getTargetMethod()); - if (!context.legacy().failsDirtyInjectionCheck() && context.legacy().hasValidSlice(dirtyTarget)) + if (!failsDirtyInjectionCheck(context, dirtyTarget) && hasValidSlice(context, config, dirtyTarget)) return PatchResult.PASS; - PatchAuditTrail.Match previousMatch = context.environment().auditTrail().getMatch(context.legacy()); - if (previousMatch != null && previousMatch != PatchAuditTrail.Match.NONE) + AuditTrail.Match previousMatch = context.environment().auditTrail().getMatch(context); + if (previousMatch != null && previousMatch != AuditTrail.Match.NONE) return PatchResult.PASS; String annotationInternalName = Type.getType(context.methodAnnotation().getDesc()).getInternalName(); @@ -47,12 +54,12 @@ public PatchResult apply(MixinContext context, Configuration config) { ClassNode cls = context.classNode(); LOGGER.debug(MIXINPATCH, "Considering method {}.{}", cls.name, cls.name); - PatchAuditTrail auditTrail = context.environment().auditTrail(); - auditTrail.recordResult(context.legacy(), PatchAuditTrail.Match.NONE); + AuditTrail auditTrail = context.environment().auditTrail(); + auditTrail.recordResult(context, config, AuditTrail.Match.NONE); PatchResult result = execute(context, config); if (result != PatchResult.PASS) { - auditTrail.recordResult(context.legacy(), PatchAuditTrail.Match.FULL); + auditTrail.recordResult(context, config, AuditTrail.Match.FULL); return result; } @@ -127,4 +134,44 @@ private PatchResult execute(MixinContext context, Configuration config) { return PatchResult.APPLY; } + + public boolean failsDirtyInjectionCheck(MixinContext context, TargetPair dirtyTarget) { + return dirtyTarget == null || !context.methods().hasInjectionTargetInsns(dirtyTarget) + && computeConstantTargetInsns(context, dirtyTarget).isEmpty(); + } + + // TODO Clean up + public List computeConstantTargetInsns(MixinContext context, @Nullable TargetPair target) { + return context.methods().computeInjectionTargetInsns( + target, + () -> context.methodAnnotation().getNested("constant").orElse(null), + (ctx, h) -> new BeforeConstant(ctx, h.unwrap(), Type.getReturnType(context.methodNode().desc).getDescriptor()), + false + ); + } + + public boolean hasValidSlice(MixinContext context, Configuration config, @Nullable TargetPair target) { + if (target == null) + return false; + + SliceData slice = config.getProperty(Keys.SLICE).orElse(null); + if (slice == null) return false; + + AtData from = slice.from(); + if (from != null && !validateAtNode(context, from, target)) + return false; + + AtData to = slice.to(); + return to == null || validateAtNode(context, to, target); + } + + private boolean validateAtNode(MixinContext context, AtData at, TargetPair target) { + List insns = context.methods().computeInjectionTargetInsns( + target, + context::injectionPointAnnotation, + (ctx, h) -> InjectionPoint.parse(ctx, context.methodNode(), context.methodAnnotation().unwrap(), at.toAnnotationNode()), + false + ); + return !insns.isEmpty(); + } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java index 31bf9656..645ad2ee 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java @@ -1,28 +1,76 @@ package org.sinytra.adapter.next.pipeline; +import com.google.common.base.Suppliers; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +// TODO Figure out Recipe and Context or merge them +// TODO Look for dirty target using clean config? /** * Defines the initial and desired states, which include mixin method metadata and per-mixin-type variables. - * - * @param clean original state before patching - * @param dirty desired state necessary to fix the mixin */ -public record Recipe(Configuration clean, Configuration dirty, Resolvers resolvers, Processors processors, MixinContext context) { +public final class Recipe { + private final Configuration clean; + private final Configuration dirty; + private final Resolvers resolvers; + private final Processors processors; + private final MixinContext context; + + private final Supplier cleanLocalsTableCache; + private final Supplier dirtyLocalsTableCache; + + /** + * @param clean original state before patching + * @param dirty desired state necessary to fix the mixin + */ + public Recipe(Configuration clean, Configuration dirty, Resolvers resolvers, Processors processors, MixinContext context) { + this.clean = clean; + this.dirty = dirty; + this.resolvers = resolvers; + this.processors = processors; + this.context = context; + + this.cleanLocalsTableCache = Suppliers.memoize(() -> Optional.ofNullable(getCleanTarget()) + .map(pair -> new LocalVariableLookup(pair.methodNode())) + .orElse(null)); + this.dirtyLocalsTableCache = Suppliers.memoize(() -> Optional.ofNullable(getDirtyTarget()) + .map(pair -> new LocalVariableLookup(pair.methodNode())) + .orElse(null)); + } + + public LocalVariableLookup cleanLocalsTable() { + return this.cleanLocalsTableCache.get(); + } + + public LocalVariableLookup dirtyLocalsTable() { + return this.dirtyLocalsTableCache.get(); + } + public Recipe withDirtyConfig(Configuration dirty) { return new Recipe(this.clean, dirty, this.resolvers, this.processors, this.context); } + // TODO Cache public TargetPair getCleanTarget() { - if (clean.getTargetMethod() == null) return null; + if (clean.getTargetMethod() == null) return null; return context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); } + public TargetPair getNewCleanTarget() { + if (clean.getTargetMethod() == null) return null; + return context.methods().findOwnMethodPair(context.dirtyLookup(), clean.getTargetMethod()); + } + public TargetPair getDirtyTarget() { if (dirty.getTargetMethod() == null) return null; return context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); @@ -32,4 +80,52 @@ public boolean hasInjectionPointValue(String value) { AtData at = clean.getAtData(); return at != null && value.equals(at.getValue()); } + + public Configuration clean() { + return clean; + } + + public Configuration dirty() { + return dirty; + } + + public Resolvers resolvers() { + return resolvers; + } + + public Processors processors() { + return processors; + } + + public MixinContext context() { + return context; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (Recipe) obj; + return Objects.equals(this.clean, that.clean) && + Objects.equals(this.dirty, that.dirty) && + Objects.equals(this.resolvers, that.resolvers) && + Objects.equals(this.processors, that.processors) && + Objects.equals(this.context, that.context); + } + + @Override + public int hashCode() { + return Objects.hash(clean, dirty, resolvers, processors, context); + } + + @Override + public String toString() { + return "Recipe[" + + "clean=" + clean + ", " + + "dirty=" + dirty + ", " + + "resolvers=" + resolvers + ", " + + "processors=" + processors + ", " + + "context=" + context + ']'; + } + } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java index aa490650..7d269453 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java @@ -16,10 +16,6 @@ public class BasePropertyContainer implements MutablePropertyContainer { @Nullable protected final PropertyContainerTemplate template; - public BasePropertyContainer() { - this(null); - } - public BasePropertyContainer(@Nullable PropertyContainerTemplate template) { this.template = template; } @@ -93,6 +89,11 @@ protected MutablePropertyContainer createCopyImpl() { return new BasePropertyContainer(this.template); } + public static MutablePropertyContainer parseValid(AnnotationHandle handle, @Nullable PropertyContainerTemplate template, RefMapper mapper) { + MutablePropertyContainer container = parse(handle, template, mapper); + return container.validate() ? container : null; + } + @SuppressWarnings({"rawtypes", "unchecked"}) public static MutablePropertyContainer parse(AnnotationHandle handle, @Nullable PropertyContainerTemplate template, RefMapper mapper) { MutablePropertyContainer container = new BasePropertyContainer(template); @@ -102,17 +103,17 @@ public static MutablePropertyContainer parse(AnnotationHandle handle, @Nullable if (value == null) continue; if (key.parser() != null) { - Object parsed = key.parser().parse(value, mapper); - container.setProperty(key, parsed); + try { + Object parsed = key.parser().parse(value, mapper); + container.setProperty(key, parsed); + } catch (Exception e) { + throw new RuntimeException("Error parsing property '%s'".formatted(key.name()), e); + } } else { throw new IllegalStateException("Cannot parse for key %s, it does not define a parser".formatted(key.name())); } } - if (!container.validate()) { - return null; - } - return container; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java index 3a4bbe5a..e62813cd 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java @@ -28,7 +28,7 @@ public final class Keys { // Resolve method reference String reference = mapper.remap(methodRefs.getFirst()); // Extract owner, name and desc using regex - return MethodQualifier.create(reference).orElse(null); + return MethodQualifier.parse(reference).orElse(null); }) .build(); public static final PropertyKey TARGET_AT = PropertyKey.builder("at") @@ -66,6 +66,7 @@ public final class Keys { .toList()) .build(); public static final PropertyKey LOCALS = PropertyKey.create("locals", LocalCapture.class); + public static final PropertyKey REQUIRE = PropertyKey.create("require", Integer.class); private Keys() { } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java index 5f9ccdac..f15d3fe4 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java @@ -13,6 +13,11 @@ static MutablePropertyContainer create(@Nullable PropertyContainerTemplate templ return new BasePropertyContainer(template); } + @Nullable + static MutablePropertyContainer parseValid(AnnotationHandle handle, @Nullable PropertyContainerTemplate template, RefMapper mapper) { + return BasePropertyContainer.parseValid(handle, template, mapper); + } + static MutablePropertyContainer parse(AnnotationHandle handle, @Nullable PropertyContainerTemplate template, RefMapper mapper) { return BasePropertyContainer.parse(handle, template, mapper); } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java index d3690984..810cce67 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java @@ -2,13 +2,13 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.ConstantData; -import org.sinytra.adapter.next.env.ann.MixinAnnotationConstants; +import org.sinytra.adapter.next.env.util.MixinAnnotationConstants; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.MixinConstants; public class InjectionTargetProcessor implements Processor { @Override @@ -19,14 +19,14 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe AnnotationHandle annotation = context.methodAnnotation(); if (dirty.getAtData() != null) { - AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_AT, MixinConstants.AT); + AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_AT, MixinAnnotations.AT); dirty.getAtData().apply(handle); } else { annotation.removeValues(MixinAnnotationConstants.PROPERTY_AT); } if (dirty.hasProperty(Keys.TARGET_CONSTANT)) { - AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_CONSTANT, MixinConstants.CONSTANT); + AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_CONSTANT, MixinAnnotations.CONSTANT); ConstantData cst = dirty.getProperty(Keys.TARGET_CONSTANT).orElseThrow(); cst.apply(handle); } else { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java index 01f2b6d9..a01a956f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java @@ -11,7 +11,7 @@ import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import java.util.List; import java.util.Map; @@ -57,7 +57,7 @@ private boolean applyDiff(List clean, List dirty, MixinContext conte ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(clean, dirty); if (!diff.isEmpty()) { PatchResult result = diff.offset(offset).asParameterTransformer(false, Set.of()) - .apply(context.legacy()); + .apply(context); return result != PatchResult.PASS; } return true; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java index 47391074..0c4236e5 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.next.pipeline.processor; -import org.sinytra.adapter.next.env.OrderedRegistry; +import org.sinytra.adapter.next.env.util.OrderedRegistry; import org.sinytra.adapter.next.pipeline.processor.extract.ExtractMixinProcessor; public class Processors extends OrderedRegistry { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java index b235f830..998ce30e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java @@ -11,7 +11,7 @@ import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.next.types.TypeAdapter; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.ArrayList; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java index a40ca273..63aea43e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java @@ -6,13 +6,12 @@ import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.patch.api.LocalVariable; -import org.sinytra.adapter.patch.api.MethodContext; +import org.sinytra.adapter.next.env.ctx.LocalVariable; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_METHOD; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_METHOD; public class TargetMethodProcessor implements Processor { @Override @@ -22,25 +21,21 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe context.methodAnnotation() .setOrAppendNonNull(AT_METHOD, List.of(dirty.getTargetMethod().asDescriptor())); - upgradeCapturedLocals(context.methodNode(), context.legacy()); + upgradeCapturedLocals(context.methodNode(), context, recipe); return TxResult.SUCCESS; } // TODO Is there a better approach? - private static void upgradeCapturedLocals(MethodNode methodNode, MethodContext methodContext) { - AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(methodNode, methodContext); - if (capturedLocals == null) { - return; - } + private static void upgradeCapturedLocals(MethodNode methodNode, MixinContext context, Recipe recipe) { + AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(context, recipe); + if (capturedLocals == null) return; - List availableLocals = methodContext.getTargetMethodLocals(capturedLocals.target()); + List availableLocals = context.methods().getTargetMethodLocals(capturedLocals.target()); // For now, only handle cases where all locals are part of the method's params, convenient when switching the target to a lambda - if (availableLocals == null || !availableLocals.isEmpty()) { - return; - } + if (availableLocals == null || !availableLocals.isEmpty()) return; LocalVarAnalyzer.CapturedLocalsTransform transform = LocalVarAnalyzer.analyzeCapturedLocals(capturedLocals, methodNode); - transform.remover().apply(methodContext); + transform.remover().apply(context); } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixin.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixin.java deleted file mode 100644 index 389709b6..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixin.java +++ /dev/null @@ -1,351 +0,0 @@ -package org.sinytra.adapter.next.pipeline.processor.extract; - -import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; -import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.OpcodeUtil; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.stream.IntStream; - -// TODO Move to processor -public record ExtractMixin(String targetClass) { - public PatchResult apply(MethodContext methodContext) { - return apply(methodContext.getMixinClass(), methodContext.getMixinMethod(), methodContext, methodContext.patchContext()); - } - - public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - // Sanity check - boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC; - - String owner = Optional.ofNullable(methodContext.findCleanInjectionTarget()).map(t -> t.classNode().name).orElse(this.targetClass); - boolean isInherited = context.environment().inheritanceHandler().isClassInherited(this.targetClass, owner); - Candidates candidates = findCandidates(classNode, methodNode); - if (!candidates.canMove(classNode, isInherited)) { - return PatchResult.PASS; - } - - ClassNode targetClass = context.environment().dirtyClassLookup().getClass(this.targetClass).orElse(null); - // Get or generate new mixin class - ClassNode generatedTarget = context.environment().classGenerator().getOrGenerateMixinClass(classNode, this.targetClass, targetClass != null ? targetClass.superName : null); - context.environment().refmapHolder().copyEntries(classNode.name, generatedTarget.name); - - // Add mixin methods from original to generated class - for (MethodNode method : candidates.methods()) { - generatedTarget.methods.add(method); - updateOwnerRefereces(method, classNode, this.targetClass); - if (!isStatic && method.localVariables != null) { - method.localVariables.stream().filter(l -> l.index == 0).findFirst().ifPresent(lvn -> lvn.desc = Type.getObjectType(generatedTarget.name).getDescriptor()); - } - } - - candidates.handleUpdates().forEach(c -> c.accept(generatedTarget)); - - // Take care of captured locals - PatchResult result = PatchResult.PASS; - if (methodContext.methodAnnotation().getValue("locals").isPresent()) { - result = result.or(recreateLocalVariables(classNode, methodNode, methodContext, context, generatedTarget)); - } - - methodContext.recordAudit(this, "Extract mixin to target %s", this.targetClass); - // Remove original method - methodContext.recordAudit(this, "Remove original method"); - context.postApply(() -> classNode.methods.removeAll(candidates.methods)); - return result.or(PatchResult.APPLY); - } - - record Candidates(List methods, List> handleUpdates) { - public boolean canMove(ClassNode classNode, boolean isInherited) { - List accessFixes = new ArrayList<>(); - for (MethodNode methodNode : this.methods) { - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof FieldInsnNode finsn && finsn.owner.equals(classNode.name) && !isInheritedField(classNode, finsn, isInherited, accessFixes) - || insn instanceof MethodInsnNode minsn && minsn.owner.equals(classNode.name) && !isInheritedMethod(classNode, minsn, isInherited, accessFixes) - ) { - // We can't move methods that access their class instance - return false; - } - } - } - accessFixes.forEach(Runnable::run); - return true; - } - } - - private static Candidates findCandidates(ClassNode classNode, MethodNode methodNode) { - List methods = new ArrayList<>(); - List> handleUpdates = new ArrayList<>(); - methods.add(methodNode); - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof InvokeDynamicInsnNode indy && indy.bsmArgs.length >= 3) { - for (int i = 0; i < indy.bsmArgs.length; i++) { - if (indy.bsmArgs[i] instanceof Handle handle && handle.getOwner().equals(classNode.name) && handle.getName().startsWith(AdapterUtil.LAMBDA_PREFIX + methodNode.name)) { - final int finalI = i; - classNode.methods.stream() - .filter(m -> m.name.equals(handle.getName()) && m.desc.equals(handle.getDesc())) - .findFirst() - .ifPresent(m -> { - methods.add(m); - handleUpdates.add(t -> indy.bsmArgs[finalI] = new Handle(handle.getTag(), t.name, handle.getName(), handle.getDesc(), handle.isInterface())); - }); - } - } - } - } - return new Candidates(methods, handleUpdates); - } - - private static void updateOwnerRefereces(MethodNode methodNode, ClassNode originalClass, String targetClass) { - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof MethodInsnNode minsn && minsn.owner.equals(originalClass.name)) { - minsn.owner = targetClass; - } else if (insn instanceof FieldInsnNode finsn && finsn.owner.equals(originalClass.name)) { - finsn.owner = targetClass; - } - } - } - - private static boolean isInheritedField(ClassNode cls, FieldInsnNode finsn, boolean isTargetInherited, List accessUpdates) { - FieldNode field = cls.fields.stream() - .filter(f -> f.name.equals(finsn.name)) - .findFirst() - .orElse(null); - if (field != null) { - if (AdapterUtil.isShadowField(field)) { - return true; - } - if (isTargetInherited) { - accessUpdates.add(() -> field.access = fixAccess(field.access)); - return true; - } - } - return false; - } - - private static boolean isInheritedMethod(ClassNode cls, MethodInsnNode minsn, boolean isTargetInherited, List accessUpdates) { - MethodNode method = cls.methods.stream() - .filter(m -> m.name.equals(minsn.name) && m.desc.equals(minsn.desc)) - .findFirst() - .orElse(null); - if (method != null) { - List annotations = method.visibleAnnotations != null ? method.visibleAnnotations : List.of(); - if (AdapterUtil.hasAnnotation(annotations, MixinConstants.SHADOW)) { - return true; - } - if (isTargetInherited) { - accessUpdates.add(() -> method.access = fixAccess(method.access)); - return true; - } - } - return false; - } - - private static int fixAccess(int access) { - int visibility = OpcodeUtil.getAccessVisibility(access); - // Lower than protected - if (visibility == Opcodes.ACC_PRIVATE || visibility == 0) { - // Widen to protected - // Add synthetic to avoid mixin complaining about non-private static members being present - // Setting the access to public will prevent the member from being renamed - return OpcodeUtil.setAccessVisibility(visibility, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC); - } - return access; - } - - /** - * We can't bring captured locals along when extracting a mixin, so our best bet is to recreate them from scratch. - *

- * Consider the following mixin injector into Gui#renderPlayerHealth, capturing 15 local variables of which only 2 are used. - *

{@code @Inject(
-     *     method = "renderPlayerHealth",
-     *     at = @At(
-     *         value = "INVOKE",
-     *         target = "someInvocation",
-     *     ),
-     *     locals = LocalCapture.CAPTURE_FAILEXCEPTION
-     * )
-     * private void renderArmor(GuiGraphics context, CallbackInfo info, Player player, int i, boolean bl, long l, int j, FoodData foodData, int k, int left, int n, int o, float f, int p, int q, int r, int top) {
-     *     return drawArmor(context, left, top);
-     * }
-     * }
- *

- * We first filter out unused captured locals. - *

{@code @Inject(
-     *     method = "renderPlayerHealth",
-     *     at = @At(
-     *         value = "INVOKE",
-     *         target = "someInvocation",
-     *     ),
-     *     locals = LocalCapture.CAPTURE_FAILEXCEPTION
-     * )
-     * private void renderArmor(GuiGraphics context, CallbackInfo info, int left, int top) {
-     *     return drawArmor(context, left, top);
-     * }
-     * }
- *

- * Next, we create a prefixed copy of the method for overloading. - * The remaining captured locals are also removed from the original, as we provide them ourselves. - *

{@code @Inject(
-     *     method = "renderPlayerHealth",
-     *     at = @At(
-     *         value = "INVOKE",
-     *         target = "someInvocation",
-     *     )
-     * )
-     * private void renderArmor(GuiGraphics context, CallbackInfo info) {
-     *
-     * }
-     *
-     * private void adapter$bridge$renderArmor(GuiGraphics context, CallbackInfo info, int left, int top) {
-     *     return drawArmor(context, left, top);
-     * }}
- *

- * Finally, we load the local variable initializer instructions and call the overloaded method. - * Local variables that are referenced multiple times in the original target's code will be stored as local variables - * in the injector for reuse. - *

{@code @Inject(
-     *     method = "renderPlayerHealth",
-     *     at = @At(
-     *         value = "INVOKE",
-     *         target = "someInvocation",
-     *     )
-     * )
-     * private void renderArmor(GuiGraphics context, CallbackInfo info) {
-     *     int shared = context.someMethod();
-     *     return adapter$bridge$renderArmor(context, shared.getLeft(), shared.getTop());
-     * }
-     *
-     * private void adapter$bridge$renderArmor(GuiGraphics context, CallbackInfo info, int left, int top) {
-     *     return drawArmor(context, left, top);
-     * }
-     * }
- */ - private static PatchResult recreateLocalVariables(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, ClassNode extractClass) { - AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(methodNode, methodContext); - if (capturedLocals == null) { - return PatchResult.PASS; - } - LocalVariableLookup table = capturedLocals.lvt(); - int paramLocalStart = capturedLocals.paramLocalStart(); - - // Mixin requires capturing locals in their original order, so we must filter out unused ones - LocalVarAnalyzer.CapturedLocalsTransform transform = LocalVarAnalyzer.analyzeCapturedLocals(capturedLocals, methodNode); - LocalVarAnalyzer.CapturedLocalsUsage usage = transform.getUsage(capturedLocals); - List used = transform.used(); - LocalVariableLookup targetTable = usage.targetTable(); - Int2ObjectMap varInsnLists = usage.varInsnLists(); - Int2IntMap usageCount = usage.usageCount(); - PatchResult result = transform.remover().apply(classNode, methodNode, methodContext, context); - if (result == PatchResult.PASS) { - return PatchResult.PASS; - } - - // Create a copy of the method to call - MethodNode copy = new MethodNode(Opcodes.ACC_PRIVATE | (capturedLocals.isStatic() ? Opcodes.ACC_STATIC : 0), "adapter$bridge$" + methodNode.name, methodNode.desc, null, null); - methodNode.accept(copy); - copy.visibleAnnotations = null; - copy.invisibleAnnotations = null; - methodNode.instructions = new InsnList(); - // Remove used locals from the original method, as we'll be providing them ourselves - TransformParameters cleanupPatch = TransformParameters.builder() - .chain(b -> IntStream.range(paramLocalStart, paramLocalStart + used.size()).boxed() - .sorted(Collections.reverseOrder()) - .forEach(b::remove)) - .build(); - PatchResult cleanupResult = cleanupPatch.apply(classNode, methodNode, methodContext, context); - if (cleanupResult == PatchResult.PASS) { - return PatchResult.PASS; - } - - // Save reused variables. Locals that are only referenced once will be inlined instead - InsnList replacementInsns = new InsnList(); - Type lastVar = Type.getType(table.getLast().desc); - AtomicInteger nextAvailableIndex = new AtomicInteger(methodNode.localVariables.size() - 1 + AdapterUtil.getLVTOffsetForType(lastVar)); - usageCount.forEach((index, count) -> { - if (count == 1) { - int usages = 0; - for (Int2ObjectMap.Entry entry : varInsnLists.int2ObjectEntrySet()) { - for (AbstractInsnNode insn : entry.getValue()) { - if (insn instanceof VarInsnNode varInsn && varInsn.var == index) { - InsnList varInitializers = varInsnLists.get(varInsn.var); - entry.getValue().insert(varInsn, varInitializers); - entry.getValue().remove(varInsn); - usages++; - } - } - } - if (usages > 1) { - throw new IllegalStateException("Expected only one reference to variable " + index); - } - } - }); - LabelNode end = new LabelNode(); - Map newIndices = new HashMap<>(); - usageCount.forEach((index, count) -> { - if (count > 1) { - LocalVariableNode node = targetTable.getByIndex(index); - Type type = Type.getType(node.desc); - int newIndex = nextAvailableIndex.getAndAdd(AdapterUtil.getLVTOffsetForType(type)); - LabelNode start = new LabelNode(); - methodNode.localVariables.add(new LocalVariableNode(node.name, node.desc, node.signature, start, end, newIndex)); - InsnList insns = varInsnLists.get((int) index); - replacementInsns.add(insns); - replacementInsns.add(new VarInsnNode(OpcodeUtil.getStoreOpcode(type.getSort()), newIndex)); - replacementInsns.add(start); - // Update initializers to point to the new index instead - varInsnLists.remove((int) index); - varInsnLists.forEach((varIndex, varInsns) -> { - for (AbstractInsnNode insn : varInsns) { - if (insn instanceof VarInsnNode varInsn && varInsn.var == index) { - varInsn.var = newIndex; - } - } - }); - newIndices.put(index, newIndex); - } - }); - - // Load parameters - for (int i = 0; i < paramLocalStart + 1; i++) { - Type type = Type.getType(table.getByIndex(i).desc); - replacementInsns.add(AdapterUtil.loadType(type, i)); - } - // Load recreated locals - used.forEach(ordinal -> { - LocalVariableNode node = targetTable.getByOrdinal(ordinal); - InsnList insns = varInsnLists.get(node.index); - if (insns != null) { - replacementInsns.add(insns); - } else { - Type type = Type.getType(node.desc); - int newIndex = newIndices.getOrDefault(node.index, -1); - if (newIndex == -1) { - throw new IllegalArgumentException("Missing new index for var " + node.index); - } - replacementInsns.add(new VarInsnNode(OpcodeUtil.getLoadOpcode(type.getSort()), newIndex)); - } - }); - // Call overloaded method - replacementInsns.add(new MethodInsnNode(capturedLocals.isStatic() ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, extractClass.name, copy.name, copy.desc)); - replacementInsns.add(new LabelNode()); - replacementInsns.add(new InsnNode(OpcodeUtil.getReturnOpcode(methodNode))); - replacementInsns.add(end); - methodNode.instructions = replacementInsns; - - extractClass.methods.add(copy); - return PatchResult.COMPUTE_FRAMES; - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java index b5572ea8..dcde16b9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java @@ -1,28 +1,370 @@ package org.sinytra.adapter.next.pipeline.processor.extract; -import org.objectweb.asm.tree.MethodInsnNode; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.TxResult; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.config.SpecialKeys; import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.next.transform.param.TransformParameters; +import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.patch.util.OpcodeUtil; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.stream.IntStream; public class ExtractMixinProcessor implements Processor { @Override public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (recipe.clean().getTargetClass().equals(dirty.getTargetClass())) return TxResult.PASS; - PatchResult result = new ExtractMixin(dirty.getTargetClass()).apply(context.legacy()); + PatchResult result = apply(dirty.getTargetClass(), context, recipe); if (result == PatchResult.PASS && dirty.hasProperty(SpecialKeys.EXTRACT_TARGET)) { MethodInsnNode minsn = dirty.getProperty(SpecialKeys.EXTRACT_TARGET).orElseThrow(); - result = new MirrorableExtractMixin(dirty.getTargetClass(), minsn).apply(context.legacy()); + result = MirrorableExtractMixin.apply(context, recipe, dirty.getTargetClass(), minsn); + } + + if (result == PatchResult.PASS) return TxResult.FAIL; + + return TxResult.SUCCESS; + } + + // TODO Prioritize mirroring over extraction, remove locals recreation + public static PatchResult apply(String targetClassName, MixinContext context, Recipe recipe) { + // Sanity check + boolean isStatic = context.isStatic(); + ClassNode classNode = context.classNode(); + MethodNode methodNode = context.methodNode(); + + TargetPair cleanTarget = recipe.getCleanTarget(); + String owner = Optional.ofNullable(cleanTarget).map(t -> t.classNode().name).orElse(targetClassName); + boolean isInherited = context.environment().inheritanceHandler().isClassInherited(targetClassName, owner); + Candidates candidates = findCandidates(classNode, methodNode); + if (!candidates.canMove(classNode, isInherited)) return PatchResult.PASS; + + ClassNode targetClass = context.environment().dirtyClassLookup().getClass(targetClassName).orElse(null); + // Get or generate new mixin class + ClassNode generatedTarget = context.environment().classGenerator().getOrGenerateMixinClass(classNode, targetClassName, targetClass != null ? targetClass.superName : null); + context.environment().refmapHolder().copyEntries(classNode.name, generatedTarget.name); + + // Add mixin methods from original to generated class + for (MethodNode method : candidates.methods()) { + generatedTarget.methods.add(method); + updateOwnerRefereces(method, classNode, targetClassName); + if (!isStatic && method.localVariables != null) { + method.localVariables.stream().filter(l -> l.index == 0).findFirst().ifPresent(lvn -> lvn.desc = Type.getObjectType(generatedTarget.name).getDescriptor()); + } + } + + candidates.handleUpdates().forEach(c -> c.accept(generatedTarget)); + + // Take care of captured locals + PatchResult result = PatchResult.PASS; + boolean capturesLocals = recipe.clean().hasProperty(Keys.LOCALS); + if (capturesLocals) { + result = result.or(recreateLocalVariables(methodNode, context, recipe, generatedTarget)); + } + + // methodContext.recordAudit(this, "Extract mixin to target %s", targetClassName); + // Remove original method + // methodContext.recordAudit(this, "Remove original method"); + context.patchContext().postApply(() -> classNode.methods.removeAll(candidates.methods)); + return result.or(PatchResult.APPLY); + } + + record Candidates(List methods, List> handleUpdates) { + public boolean canMove(ClassNode classNode, boolean isInherited) { + List accessFixes = new ArrayList<>(); + for (MethodNode methodNode : this.methods) { + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof FieldInsnNode finsn && finsn.owner.equals(classNode.name) && !isInheritedField(classNode, finsn, isInherited, accessFixes) + || insn instanceof MethodInsnNode minsn && minsn.owner.equals(classNode.name) && !isInheritedMethod(classNode, minsn, isInherited, accessFixes) + ) { + // We can't move methods that access their class instance + return false; + } + } + } + accessFixes.forEach(Runnable::run); + return true; + } + } + + private static Candidates findCandidates(ClassNode classNode, MethodNode methodNode) { + List methods = new ArrayList<>(); + List> handleUpdates = new ArrayList<>(); + methods.add(methodNode); + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof InvokeDynamicInsnNode indy && indy.bsmArgs.length >= 3) { + for (int i = 0; i < indy.bsmArgs.length; i++) { + if (indy.bsmArgs[i] instanceof Handle handle && handle.getOwner().equals(classNode.name) && handle.getName().startsWith(AdapterUtil.LAMBDA_PREFIX + methodNode.name)) { + final int finalI = i; + classNode.methods.stream() + .filter(m -> m.name.equals(handle.getName()) && m.desc.equals(handle.getDesc())) + .findFirst() + .ifPresent(m -> { + methods.add(m); + handleUpdates.add(t -> indy.bsmArgs[finalI] = new Handle(handle.getTag(), t.name, handle.getName(), handle.getDesc(), handle.isInterface())); + }); + } + } + } + } + return new Candidates(methods, handleUpdates); + } + + private static void updateOwnerRefereces(MethodNode methodNode, ClassNode originalClass, String targetClass) { + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof MethodInsnNode minsn && minsn.owner.equals(originalClass.name)) { + minsn.owner = targetClass; + } else if (insn instanceof FieldInsnNode finsn && finsn.owner.equals(originalClass.name)) { + finsn.owner = targetClass; + } + } + } + + private static boolean isInheritedField(ClassNode cls, FieldInsnNode finsn, boolean isTargetInherited, List accessUpdates) { + FieldNode field = cls.fields.stream() + .filter(f -> f.name.equals(finsn.name)) + .findFirst() + .orElse(null); + if (field != null) { + if (AdapterUtil.isShadowField(field)) { + return true; + } + if (isTargetInherited) { + accessUpdates.add(() -> field.access = fixAccess(field.access)); + return true; + } + } + return false; + } + + private static boolean isInheritedMethod(ClassNode cls, MethodInsnNode minsn, boolean isTargetInherited, List accessUpdates) { + MethodNode method = cls.methods.stream() + .filter(m -> m.name.equals(minsn.name) && m.desc.equals(minsn.desc)) + .findFirst() + .orElse(null); + if (method != null) { + List annotations = method.visibleAnnotations != null ? method.visibleAnnotations : List.of(); + if (AdapterUtil.hasAnnotation(annotations, MixinAnnotations.SHADOW)) { + return true; + } + if (isTargetInherited) { + accessUpdates.add(() -> method.access = fixAccess(method.access)); + return true; + } + } + return false; + } + + private static int fixAccess(int access) { + int visibility = OpcodeUtil.getAccessVisibility(access); + // Lower than protected + if (visibility == Opcodes.ACC_PRIVATE || visibility == 0) { + // Widen to protected + // Add synthetic to avoid mixin complaining about non-private static members being present + // Setting the access to public will prevent the member from being renamed + return OpcodeUtil.setAccessVisibility(visibility, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC); } + return access; + } + + /** + * We can't bring captured locals along when extracting a mixin, so our best bet is to recreate them from scratch. + *

+ * Consider the following mixin injector into Gui#renderPlayerHealth, capturing 15 local variables of which only 2 are used. + *

{@code @Inject(
+     *     method = "renderPlayerHealth",
+     *     at = @At(
+     *         value = "INVOKE",
+     *         target = "someInvocation",
+     *     ),
+     *     locals = LocalCapture.CAPTURE_FAILEXCEPTION
+     * )
+     * private void renderArmor(GuiGraphics context, CallbackInfo info, Player player, int i, boolean bl, long l, int j, FoodData foodData, int k, int left, int n, int o, float f, int p, int q, int r, int top) {
+     *     return drawArmor(context, left, top);
+     * }
+     * }
+ *

+ * We first filter out unused captured locals. + *

{@code @Inject(
+     *     method = "renderPlayerHealth",
+     *     at = @At(
+     *         value = "INVOKE",
+     *         target = "someInvocation",
+     *     ),
+     *     locals = LocalCapture.CAPTURE_FAILEXCEPTION
+     * )
+     * private void renderArmor(GuiGraphics context, CallbackInfo info, int left, int top) {
+     *     return drawArmor(context, left, top);
+     * }
+     * }
+ *

+ * Next, we create a prefixed copy of the method for overloading. + * The remaining captured locals are also removed from the original, as we provide them ourselves. + *

{@code @Inject(
+     *     method = "renderPlayerHealth",
+     *     at = @At(
+     *         value = "INVOKE",
+     *         target = "someInvocation",
+     *     )
+     * )
+     * private void renderArmor(GuiGraphics context, CallbackInfo info) {
+     *
+     * }
+     *
+     * private void adapter$bridge$renderArmor(GuiGraphics context, CallbackInfo info, int left, int top) {
+     *     return drawArmor(context, left, top);
+     * }}
+ *

+ * Finally, we load the local variable initializer instructions and call the overloaded method. + * Local variables that are referenced multiple times in the original target's code will be stored as local variables + * in the injector for reuse. + *

{@code @Inject(
+     *     method = "renderPlayerHealth",
+     *     at = @At(
+     *         value = "INVOKE",
+     *         target = "someInvocation",
+     *     )
+     * )
+     * private void renderArmor(GuiGraphics context, CallbackInfo info) {
+     *     int shared = context.someMethod();
+     *     return adapter$bridge$renderArmor(context, shared.getLeft(), shared.getTop());
+     * }
+     *
+     * private void adapter$bridge$renderArmor(GuiGraphics context, CallbackInfo info, int left, int top) {
+     *     return drawArmor(context, left, top);
+     * }
+     * }
+ */ + private static PatchResult recreateLocalVariables(MethodNode methodNode, MixinContext context, Recipe recipe, ClassNode extractClass) { + AdapterUtil.CapturedLocals capturedLocals = AdapterUtil.getCapturedLocals(context, recipe); + if (capturedLocals == null) { + return PatchResult.PASS; + } + LocalVariableLookup table = capturedLocals.lvt(); + int paramLocalStart = capturedLocals.paramLocalStart(); + + // Mixin requires capturing locals in their original order, so we must filter out unused ones + LocalVarAnalyzer.CapturedLocalsTransform transform = LocalVarAnalyzer.analyzeCapturedLocals(capturedLocals, methodNode); + LocalVarAnalyzer.CapturedLocalsUsage usage = transform.getUsage(capturedLocals); + List used = transform.used(); + LocalVariableLookup targetTable = usage.targetTable(); + Int2ObjectMap varInsnLists = usage.varInsnLists(); + Int2IntMap usageCount = usage.usageCount(); + PatchResult result = transform.remover().apply(context); if (result == PatchResult.PASS) { - return TxResult.FAIL; + return PatchResult.PASS; } - return TxResult.SUCCESS; + // Create a copy of the method to call + MethodNode copy = new MethodNode(Opcodes.ACC_PRIVATE | (capturedLocals.isStatic() ? Opcodes.ACC_STATIC : 0), "adapter$bridge$" + methodNode.name, methodNode.desc, null, null); + methodNode.accept(copy); + copy.visibleAnnotations = null; + copy.invisibleAnnotations = null; + methodNode.instructions = new InsnList(); + // Remove used locals from the original method, as we'll be providing them ourselves + TransformParameters cleanupPatch = TransformParameters.builder() + .chain(b -> IntStream.range(paramLocalStart, paramLocalStart + used.size()).boxed() + .sorted(Collections.reverseOrder()) + .forEach(b::remove)) + .build(); + PatchResult cleanupResult = cleanupPatch.apply(context); + if (cleanupResult == PatchResult.PASS) { + return PatchResult.PASS; + } + + // Save reused variables. Locals that are only referenced once will be inlined instead + InsnList replacementInsns = new InsnList(); + Type lastVar = Type.getType(table.getLast().desc); + AtomicInteger nextAvailableIndex = new AtomicInteger(methodNode.localVariables.size() - 1 + AdapterUtil.getLVTOffsetForType(lastVar)); + usageCount.forEach((index, count) -> { + if (count == 1) { + int usages = 0; + for (Int2ObjectMap.Entry entry : varInsnLists.int2ObjectEntrySet()) { + for (AbstractInsnNode insn : entry.getValue()) { + if (insn instanceof VarInsnNode varInsn && varInsn.var == index) { + InsnList varInitializers = varInsnLists.get(varInsn.var); + entry.getValue().insert(varInsn, varInitializers); + entry.getValue().remove(varInsn); + usages++; + } + } + } + if (usages > 1) { + throw new IllegalStateException("Expected only one reference to variable " + index); + } + } + }); + LabelNode end = new LabelNode(); + Map newIndices = new HashMap<>(); + usageCount.forEach((index, count) -> { + if (count > 1) { + LocalVariableNode node = targetTable.getByIndex(index); + Type type = Type.getType(node.desc); + int newIndex = nextAvailableIndex.getAndAdd(AdapterUtil.getLVTOffsetForType(type)); + LabelNode start = new LabelNode(); + methodNode.localVariables.add(new LocalVariableNode(node.name, node.desc, node.signature, start, end, newIndex)); + InsnList insns = varInsnLists.get((int) index); + replacementInsns.add(insns); + replacementInsns.add(new VarInsnNode(OpcodeUtil.getStoreOpcode(type.getSort()), newIndex)); + replacementInsns.add(start); + // Update initializers to point to the new index instead + varInsnLists.remove((int) index); + varInsnLists.forEach((varIndex, varInsns) -> { + for (AbstractInsnNode insn : varInsns) { + if (insn instanceof VarInsnNode varInsn && varInsn.var == index) { + varInsn.var = newIndex; + } + } + }); + newIndices.put(index, newIndex); + } + }); + + // Load parameters + for (int i = 0; i < paramLocalStart + 1; i++) { + Type type = Type.getType(table.getByIndex(i).desc); + replacementInsns.add(AdapterUtil.loadType(type, i)); + } + // Load recreated locals + used.forEach(ordinal -> { + LocalVariableNode node = targetTable.getByOrdinal(ordinal); + InsnList insns = varInsnLists.get(node.index); + if (insns != null) { + replacementInsns.add(insns); + } else { + Type type = Type.getType(node.desc); + int newIndex = newIndices.getOrDefault(node.index, -1); + if (newIndex == -1) { + throw new IllegalArgumentException("Missing new index for var " + node.index); + } + replacementInsns.add(new VarInsnNode(OpcodeUtil.getLoadOpcode(type.getSort()), newIndex)); + } + }); + // Call overloaded method + replacementInsns.add(new MethodInsnNode(capturedLocals.isStatic() ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, extractClass.name, copy.name, copy.desc)); + replacementInsns.add(new LabelNode()); + replacementInsns.add(new InsnNode(OpcodeUtil.getReturnOpcode(methodNode))); + replacementInsns.add(end); + methodNode.instructions = replacementInsns; + + extractClass.methods.add(copy); + return PatchResult.COMPUTE_FRAMES; } } diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java index dac911c4..ea02cc14 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java @@ -6,10 +6,14 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.PatchEnvironment; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.env.util.MixinAnnotations; +import org.sinytra.adapter.next.env.util.TypeConstants; +import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -19,13 +23,21 @@ import java.util.List; import java.util.stream.Stream; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_METHOD; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_METHOD; // TODO Cleanup -public record MirrorableExtractMixin(String destinationClass, MethodInsnNode destinationMethodInvocation) { - public PatchResult apply(MethodContext methodContext) { - Type selfType = Type.getObjectType(methodContext.findDirtyInjectionTarget().classNode().name); - Type[] params = Type.getArgumentTypes(this.destinationMethodInvocation.desc); +public class MirrorableExtractMixin { + + public static PatchResult apply(MixinContext context, Recipe recipe, String destinationClass, MethodInsnNode destinationMethodInvocation) { + TargetPair dirtyTarget = recipe.getNewCleanTarget(); + if (dirtyTarget == null) return PatchResult.PASS; + + ClassNode classNode = context.classNode(); + MethodNode methodNode = context.methodNode(); + PatchEnvironment environment = context.environment(); + + Type selfType = Type.getObjectType(dirtyTarget.classNode().name); + Type[] params = Type.getArgumentTypes(destinationMethodInvocation.desc); int selfIndex = Stream.of(Stream.iterate(0, i -> i < params.length, i -> i + 1) .filter(i -> params[i].equals(selfType)) .toList()) @@ -37,7 +49,7 @@ public PatchResult apply(MethodContext methodContext) { return PatchResult.PASS; } - List callInsns = MethodCallAnalyzer.getMethodCallSrcInsns(methodContext.findDirtyInjectionTarget().methodNode(), this.destinationMethodInvocation); + List callInsns = MethodCallAnalyzer.getMethodCallSrcInsns(dirtyTarget.methodNode(), destinationMethodInvocation); if (callInsns == null || callInsns.size() <= selfIndex) { return PatchResult.PASS; } @@ -46,13 +58,12 @@ public PatchResult apply(MethodContext methodContext) { return PatchResult.PASS; } // Cool, out instance is passed into the method. Now let's inject there and call the old mixin method - ClassNode generatedTarget = methodContext.patchContext().environment().classGenerator().getOrGenerateMixinClass(methodContext.getMixinClass(), this.destinationClass, null); - methodContext.patchContext().environment().refmapHolder().copyEntries(methodContext.getMixinClass().name, generatedTarget.name); + ClassNode generatedTarget = environment.classGenerator().getOrGenerateMixinClass(classNode, destinationClass, null); + environment.refmapHolder().copyEntries(classNode.name, generatedTarget.name); // Generate a method with the same injector annotation - MethodNode originalMixinMethod = methodContext.getMixinMethod(); - String name = originalMixinMethod.name + "$adapter$mirror$" + AdapterUtil.randomString(5); - List originalParams = List.of(Type.getArgumentTypes(originalMixinMethod.desc)); - List newParams = ImmutableList.builder().add(Type.getArgumentTypes(this.destinationMethodInvocation.desc)).add(MixinConstants.CI_TYPE).build(); + String name = methodNode.name + "$adapter$mirror$" + AdapterUtil.randomString(5); + List originalParams = List.of(Type.getArgumentTypes(methodNode.desc)); + List newParams = ImmutableList.builder().add(Type.getArgumentTypes(destinationMethodInvocation.desc)).add(TypeConstants.CI_TYPE).build(); // Make sure we have all required params if (!new HashSet<>(newParams).containsAll(originalParams)) { return PatchResult.PASS; @@ -60,17 +71,17 @@ public PatchResult apply(MethodContext methodContext) { String desc = Type.getMethodDescriptor(Type.VOID_TYPE, newParams.toArray(Type[]::new)); // Change target - methodContext.methodAnnotation() + context.methodAnnotation() .setOrAppendNonNull(AT_METHOD, List.of( MethodQualifier.create(destinationMethodInvocation).asDescriptor() )); MethodNode invokerMixinMethod = (MethodNode) generatedTarget.visitMethod(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, name, desc, null, null); - invokerMixinMethod.visibleAnnotations = new ArrayList<>(originalMixinMethod.visibleAnnotations); + invokerMixinMethod.visibleAnnotations = new ArrayList<>(methodNode.visibleAnnotations); // Make original mixin a unique public method - originalMixinMethod.access = OpcodeUtil.setAccessVisibility(originalMixinMethod.access, Opcodes.ACC_PUBLIC); - originalMixinMethod.visibleAnnotations.remove(methodContext.methodAnnotation().unwrap()); - originalMixinMethod.visitAnnotation(MixinConstants.UNIQUE, true); + methodNode.access = OpcodeUtil.setAccessVisibility(methodNode.access, Opcodes.ACC_PUBLIC); + methodNode.visibleAnnotations.remove(context.methodAnnotation().unwrap()); + methodNode.visitAnnotation(MixinAnnotations.UNIQUE, true); // Now call the original mixin GeneratorAdapter gen = new GeneratorAdapter(invokerMixinMethod, invokerMixinMethod.access, invokerMixinMethod.name, invokerMixinMethod.desc); gen.newLabel(); @@ -78,7 +89,7 @@ public PatchResult apply(MethodContext methodContext) { for (Type type : originalParams) { gen.loadArg(newParams.indexOf(type)); } - gen.invokeVirtual(selfType, new Method(originalMixinMethod.name, originalMixinMethod.desc)); + gen.invokeVirtual(selfType, new Method(methodNode.name, methodNode.desc)); gen.newLabel(); gen.returnValue(); gen.newLabel(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java index cd00703a..6c6f2a3e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java @@ -13,7 +13,7 @@ import java.util.function.Consumer; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class DivertRedirectProcessor implements Processor { @Override @@ -22,7 +22,7 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe if (patcher == null) return TxResult.PASS; if (!recipe.hasInjectionPointValue(AT_VAL_INVOKE)) return TxResult.PASS; - MethodQualifier target = dirty.getAtData().getTarget().flatMap(MethodQualifier::create).orElse(null); + MethodQualifier target = dirty.getAtData().getTarget().flatMap(MethodQualifier::parse).orElse(null); if (target != null) { MethodNode methodNode = context.methodNode(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java index d8483d31..bf99f6a5 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java @@ -17,8 +17,8 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe String dirtyTarget = dirty.getAtData().getTarget().orElse(null); if (dirtyTarget == null) return TxResult.PASS; - MethodQualifier cleanTargetQual = MethodQualifier.create(cleanTarget).orElseThrow(); - MethodQualifier dirtyTargetQual = MethodQualifier.create(dirtyTarget).orElseThrow(); + MethodQualifier cleanTargetQual = MethodQualifier.parse(cleanTarget).orElseThrow(); + MethodQualifier dirtyTargetQual = MethodQualifier.parse(dirtyTarget).orElseThrow(); for (AbstractInsnNode insn : context.methodNode().instructions) { if (insn instanceof MethodInsnNode minsn && cleanTargetQual.matches(minsn)) { if (dirtyTargetQual.owner() != null) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java index 7b447125..ad6e358f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java @@ -11,9 +11,9 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; -import org.sinytra.adapter.patch.fixes.TypeAdapter; -import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil; +import org.sinytra.adapter.next.types.BytecodeFixerUpper; +import org.sinytra.adapter.next.types.TypeAdapter; +import org.sinytra.adapter.next.transform.param.ParamTransformationUtil; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.OpcodeUtil; @@ -68,7 +68,7 @@ public static boolean tryUpgrade(MixinContext context, Recipe recipe, List return null; } - LocalVariableLookup cleanLookup = context.legacy().cleanLocalsTable(); + LocalVariableLookup cleanLookup = recipe.cleanLocalsTable(); LocalVariableNode lvn = cleanLookup.getByIndex(varInsn.var); TypeAdapter typeAdapter = bfu.getTypeAdapter(Type.getObjectType(dirtyInsn.owner), Type.getType(lvn.desc)); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java index 846e6a64..326df5bd 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.next.pipeline.resolver; -import org.sinytra.adapter.next.env.OrderedRegistry; +import org.sinytra.adapter.next.env.util.OrderedRegistry; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.next.pipeline.resolver.special.SliceBoundaryResolver; import org.sinytra.adapter.next.pipeline.resolver.target.TargetMethodResolver; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java index 26a97b06..a3b5680d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java @@ -5,6 +5,7 @@ import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; @@ -12,8 +13,7 @@ import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -22,7 +22,7 @@ import java.util.function.Function; import java.util.function.UnaryOperator; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class ArbitraryInjectionPointSubResolver implements SubResolver { @Nullable @@ -94,7 +94,7 @@ private static AbstractInsnNode findCandidates(InstructionMatcher cleanMatcher, private static MethodInsnNode findReplacementInjectionPoint(AbstractInsnNode lastInsn, UnaryOperator flow, MixinContext context, String injectionPointTarget) { // Require matching return types for ModifyExpressionValue mixins // TODO Eliminate use of matchesDesc - if (context.methodAnnotation().matchesDesc(MixinConstants.MODIFY_EXPR_VAL)) { + if (context.methodAnnotation().matchesDesc(MixinAnnotations.MODIFY_EXPR_VAL)) { Type desiredReturnType = Type.getReturnType(injectionPointTarget); return (MethodInsnNode) AdapterUtil.iterateInsns(lastInsn, flow, v -> v instanceof MethodInsnNode minsn && Type.getReturnType(minsn.desc).equals(desiredReturnType)); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java index 3335a73c..24ca19e1 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java @@ -3,19 +3,19 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.OpcodeUtil; import java.util.ArrayList; import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; /** * Find our new injection point with relation to variable assignments @@ -39,12 +39,12 @@ public Configuration resolve(MixinContext context, Recipe recipe) { return null; } // Find matching local in dirty target method - LocalVariableNode cleanLocal = context.legacy().cleanLocalsTable().getByIndexOrNull(varInsn.var); + LocalVariableNode cleanLocal = recipe.cleanLocalsTable().getByIndexOrNull(varInsn.var); if (cleanLocal == null) { return null; } - List cleanLocals = context.legacy().cleanLocalsTable().getForType(cleanLocal); - List dirtyLocals = context.legacy().dirtyLocalsTable().getForType(cleanLocal); + List cleanLocals = recipe.cleanLocalsTable().getForType(cleanLocal); + List dirtyLocals = recipe.dirtyLocalsTable().getForType(cleanLocal); if (cleanLocals.size() != dirtyLocals.size()) { return null; } @@ -66,7 +66,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { return null; } - if (context.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { + if (context.methodAnnotation().matchesDesc(MixinAnnotations.WRAP_OPERATION)) { // In case the mixin is call-sensitive, we try to keep the orignal injection point if the method was moved if (!previousMethodCall.owner.equals(dirtyPair.classNode().name)) { return null; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java index a6e90f13..58bb8934 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java @@ -8,9 +8,12 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; import org.sinytra.adapter.next.env.ann.ConstantData; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup; import org.sinytra.adapter.next.env.param.Parameter; +import org.sinytra.adapter.next.env.util.MixinAnnotations; +import org.sinytra.adapter.next.env.util.TypeConstants; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.Keys; @@ -21,17 +24,14 @@ import org.sinytra.adapter.patch.analysis.MethodLabelComparator; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.Collection; import java.util.List; import java.util.Optional; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.PROPERTY_ORDINAL; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.PROPERTY_ORDINAL; public abstract class ComparingInjectionPointResolver implements SubResolver { @@ -54,7 +54,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { if (cleanTarget == null) return null; AbstractInsnNode cleanInsn = prepare(context, recipe); - MethodLabelComparator.ComparisonResult comparisonResult = MethodLabelComparator.findPatchedLabels(cleanInsn, context.legacy()); + MethodLabelComparator.ComparisonResult comparisonResult = MethodLabelComparator.findPatchedLabels(cleanInsn, recipe); if (comparisonResult == null) return null; List> hunkLabels = comparisonResult.patchedLabels(); @@ -111,7 +111,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { AbstractInsnNode cleanInsn = prepare(context, recipe); if (!(cleanInsn instanceof MethodInsnNode minsn)) return null; - MethodLabelComparator.ComparisonResult comparisonResult = MethodLabelComparator.findPatchedLabels(cleanInsn, context.legacy()); + MethodLabelComparator.ComparisonResult comparisonResult = MethodLabelComparator.findPatchedLabels(cleanInsn, recipe); if (comparisonResult == null) return null; List> hunkLabels = comparisonResult.patchedLabels(); @@ -151,20 +151,22 @@ private static Optional handleWrapOperationToInstanceOf(Recipe re .inheritParameters() .inheritReturnType(); MethodParameters parameters = config.getParameters(); - Parameter newInstanceParam = Parameter.simple(MixinConstants.OBJECT_TYPE); + Parameter newInstanceParam = Parameter.simple(TypeConstants.OBJECT_TYPE); parameters.set(ParamGroup.METHOD_PARAMS, List.of(newInstanceParam)); if (usedVars.containsKey(instanceLocal.index)) { - MethodContext methodContext = context.legacy(); - List originalCallArgs = MethodCallAnalyzer.getMethodCallSrcInsns(methodContext.findCleanInjectionTarget().methodNode(), cleanInjectionInsn); - int cleanOrdinal = methodContext.cleanLocalsTable().getTypedOrdinal(methodContext.cleanLocalsTable().getByIndex(((VarInsnNode) originalCallArgs.getFirst()).var)).orElse(-1); + TargetPair cleanTarget = recipe.getCleanTarget(); + LocalVariableLookup cleanLocals = recipe.cleanLocalsTable(); + + List originalCallArgs = MethodCallAnalyzer.getMethodCallSrcInsns(cleanTarget.methodNode(), cleanInjectionInsn); + int cleanOrdinal = cleanLocals.getTypedOrdinal(cleanLocals.getByIndex(((VarInsnNode) originalCallArgs.getFirst()).var)).orElse(-1); if (cleanOrdinal == -1) return Optional.empty(); - LocalVariableNode dirtyLocal = methodContext.dirtyLocalsTable().getByTypedOrdinal(Type.getType(instanceLocal.desc), cleanOrdinal).orElse(null); + LocalVariableNode dirtyLocal = recipe.dirtyLocalsTable().getByTypedOrdinal(Type.getType(instanceLocal.desc), cleanOrdinal).orElse(null); if (dirtyLocal == null) return Optional.empty(); Parameter replacementInstanceParam = Parameter.builder(dirtyLocal.desc) - .annotate(MixinConstants.LOCAL, b -> b + .annotate(MixinAnnotations.LOCAL, b -> b .put(PROPERTY_ORDINAL, cleanOrdinal)) .build(); parameters.add(ParamGroup.LOCALS, replacementInstanceParam); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java index 723aa8fd..eb5c9a3c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java @@ -11,19 +11,19 @@ import org.sinytra.adapter.next.env.param.MethodParameters; import org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup; import org.sinytra.adapter.next.env.param.Parameter; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.TargetPair; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; +import org.sinytra.adapter.next.env.ctx.PatchContext; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.types.BytecodeFixerUpper; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; // TODO Test public class InheritedInjectionPointSubResolver implements SubResolver { @@ -33,7 +33,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { if (!recipe.hasInjectionPointValue(AT_VAL_INVOKE)) return null; AtData at = recipe.clean().getAtData(); - MethodQualifier atTarget = at.getTarget().flatMap(MethodQualifier::create).orElseThrow(); + MethodQualifier atTarget = at.getTarget().flatMap(MethodQualifier::parse).orElseThrow(); if (atTarget == null) return null; TargetPair targetPair = recipe.getDirtyTarget(); @@ -51,12 +51,12 @@ public Configuration resolve(MixinContext context, Recipe recipe) { MutableConfiguration config = MutableConfiguration.create(); config.setAtData(at.withTarget(minsn)); - if (context.methodAnnotation().matchesDesc(MixinConstants.REDIRECT) && minsn.getOpcode() != Opcodes.INVOKESTATIC) { + if (context.methodAnnotation().matchesDesc(MixinAnnotations.REDIRECT) && minsn.getOpcode() != Opcodes.INVOKESTATIC) { MethodParameters params = recipe.clean().getParameters().copy(); List callParams = params.get(ParamGroup.METHOD_PARAMS); if (!callParams.isEmpty()) { Parameter first = callParams.getFirst().extend() - .annotate(MixinConstants.COERCE, b -> b.visible(false)) + .annotate(MixinAnnotations.COERCE, b -> b.visible(false)) .build(); callParams.set(0, first); config.setParameters(params); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java index bde6baae..a3c49a00 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java @@ -6,7 +6,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java index f4b4a979..ec5bfd2e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java @@ -7,7 +7,7 @@ import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.WeighedDisambiguation; +import org.sinytra.adapter.next.env.util.WeighedDisambiguation; import org.sinytra.adapter.next.env.param.Parameters; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; @@ -15,14 +15,14 @@ import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class InjectionPointSubResolvers { public static final SubResolver REPLACED_TYPE = (MixinContext context, Recipe recipe) -> { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java index cd139b6b..5b32d8a9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java @@ -12,11 +12,11 @@ import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_STORE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_STORE; import static org.sinytra.adapter.next.pipeline.config.Keys.ORDINAL; public class ModifyVarInjectionPointSubResolver implements SubResolver { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java index 38fd2c7c..58fae008 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java @@ -8,6 +8,9 @@ import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.ctx.PatchContext; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.Keys; @@ -19,9 +22,6 @@ import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.GeneratedVariables; import org.sinytra.adapter.patch.util.SingleValueHandle; @@ -29,8 +29,8 @@ import java.util.*; import java.util.function.Function; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_RETURN; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_RETURN; public class InjectorOrdinalResolver implements Resolver { private static final Map OFFSET_HANDLERS = Map.of( @@ -43,7 +43,7 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { Type returnType = recipe.clean().getReturnType(); if (returnType == null) return ResolutionResult.pass(); - List> offsetHandlers = getOffsetHandlers(context, recipe.clean(), returnType); + List> offsetHandlers = getOffsetHandlers(context, recipe, returnType); if (offsetHandlers.isEmpty()) return ResolutionResult.pass(); TargetPair cleanTarget = recipe.getCleanTarget(); @@ -65,7 +65,8 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { return applied ? ResolutionResult.success(merged) : ResolutionResult.pass(); } - private static List> getOffsetHandlers(MixinContext context, Configuration cleanConfig, Type returnType) { + private static List> getOffsetHandlers(MixinContext context, Recipe recipe, Type returnType) { + Configuration cleanConfig = recipe.clean(); AtData at = cleanConfig.getAtData(); List> handlers = new ArrayList<>(); @@ -82,8 +83,8 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { } }); - if (context.methodAnnotation().matchesDesc(MixinConstants.MODIFY_VAR)) { - LocalVariableLookup cleanTable = context.legacy().cleanLocalsTable(); + if (context.methodAnnotation().matchesDesc(MixinAnnotations.MODIFY_VAR)) { + LocalVariableLookup cleanTable = recipe.cleanLocalsTable(); if (cleanTable != null) { // Handle modified ordinals cleanConfig.getProperty(Keys.ORDINAL) diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java index d42428ca..af923749 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java @@ -7,22 +7,22 @@ import org.objectweb.asm.tree.VarInsnNode; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.pipeline.resolver.Resolver; import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.TargetPair; -import org.sinytra.adapter.patch.util.MockMixinRuntime; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.env.MockMixinRuntime; import org.spongepowered.asm.mixin.injection.modify.LocalVariableDiscriminator; import org.spongepowered.asm.mixin.injection.struct.InjectionInfo; import org.spongepowered.asm.mixin.injection.struct.Target; import java.util.List; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_RETURN; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_RETURN; /** * Original mixin: @@ -106,7 +106,7 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { AbstractInsnNode insn = args.get(i); if (insn instanceof VarInsnNode varInsn && varInsn.var == cleanTargetPair.getSecond()) { Configuration config = recipe.dirty().copyClean() - .setMixinType(MixinConstants.MODIFY_ARG) + .setMixinType(MixinAnnotations.MODIFY_ARG) .inheritTargetClass() .inheritTargetMethod() .setAtData(AtData.create(AT_VAL_INVOKE, dirtyMinsn)) diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java index d9c766b7..f2514fa9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java @@ -2,14 +2,14 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.patch.api.MixinConstants; import org.spongepowered.asm.mixin.injection.At; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN; /** * Upgrade a ModifyVar to a ModifyExpressionVal @@ -82,7 +82,7 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { String target = at.getTargetOrThrow(); Configuration config = recipe.dirty().copyClean() - .setMixinType(MixinConstants.MODIFY_EXPR_VAL) + .setMixinType(MixinAnnotations.MODIFY_EXPR_VAL) .inheritTargetClass() .inheritTargetMethod() .setAtData(AtData.create(AT_VAL_INVOKE, target)) diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java index 28a641cb..62ba08d9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java @@ -5,21 +5,21 @@ import org.sinytra.adapter.next.env.Configurations; import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.ann.AtData; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.Resolver; import org.sinytra.adapter.patch.analysis.InsnComparator; import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import java.util.ArrayList; import java.util.List; import java.util.Map; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_SINYTRA_INSTANCEOF; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_SINYTRA_INSTANCEOF; /** *

@@ -65,7 +65,7 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { int ordinal = getInstanceofOrdinal(dirtyInsns, instanceOfInsn); Configuration config = recipe.dirty().copyClean() - .setMixinType(MixinConstants.MODIFY_INSTANCEOF_VAL) + .setMixinType(MixinAnnotations.MODIFY_INSTANCEOF_VAL) .inheritTargetClass() .inheritTargetMethod() .setAtData(AtData.builder(AT_VAL_SINYTRA_INSTANCEOF) diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java index 383b8917..ed51817b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java @@ -12,9 +12,9 @@ import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.MockMixinRuntime; +import org.sinytra.adapter.next.env.MockMixinRuntime; import org.spongepowered.asm.mixin.injection.code.ISliceContext; import org.spongepowered.asm.mixin.injection.code.MethodSlice; import org.spongepowered.asm.mixin.injection.struct.Target; @@ -24,7 +24,7 @@ import java.util.List; import java.util.Optional; -import static org.sinytra.adapter.next.env.ann.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; import static org.sinytra.adapter.next.pipeline.config.Keys.SLICE; public class SliceBoundaryResolver implements Resolver { @@ -69,7 +69,7 @@ private static Optional fixSlideInjectionPoint(AtData boundary, MethodNo return Optional.empty(); // Find original target invocation qualifier - MethodQualifier target = boundary.getTarget().flatMap(MethodQualifier::create).orElse(null); + MethodQualifier target = boundary.getTarget().flatMap(MethodQualifier::parse).orElse(null); if (target == null) return Optional.empty(); // Find method invocations with a matching name diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java index 54b89594..4b7d4854 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java @@ -8,11 +8,12 @@ import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.api.MixinClassGenerator; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.MixinClassGenerator; +import org.sinytra.adapter.next.env.util.TypeConstants; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -20,7 +21,7 @@ public final class SplitMethodCancellationHelper { - public static void handle(Object transform, MixinContext context, Recipe recipe, MethodNode newTarget) { + public static void handle(MixinContext context, Recipe recipe, MethodNode newTarget) { TargetPair cleanTarget = recipe.getCleanTarget(); TargetPair originalTarget = recipe.getDirtyTarget(); @@ -53,10 +54,10 @@ public static void handle(Object transform, MixinContext context, Recipe recipe, private static void generateCancellerMethod(ClassNode generatedTarget, FieldNode trackerField, ClassNode originalClassTarget, MethodNode newTarget, MixinContext context, boolean reset) { String name = context.methodNode().name + "$adapter$canceller$" + AdapterUtil.randomString(5); - String desc = Type.getMethodDescriptor(Type.VOID_TYPE, MixinConstants.CI_TYPE); + String desc = Type.getMethodDescriptor(Type.VOID_TYPE, TypeConstants.CI_TYPE); MethodNode invokerMixinMethod = (MethodNode) generatedTarget.visitMethod(Opcodes.ACC_PRIVATE | (context.isStatic() ? Opcodes.ACC_STATIC : 0), name, desc, null, null); { - AnnotationVisitor injectAnn = invokerMixinMethod.visitAnnotation(MixinConstants.INJECT, true); + AnnotationVisitor injectAnn = invokerMixinMethod.visitAnnotation(MixinAnnotations.INJECT, true); { AnnotationVisitor methodValue = injectAnn.visitArray("method"); methodValue.visit(null, newTarget.name + newTarget.desc); @@ -65,7 +66,7 @@ private static void generateCancellerMethod(ClassNode generatedTarget, FieldNode { AnnotationVisitor atValue = injectAnn.visitArray("at"); { - AnnotationVisitor atAnn = atValue.visitAnnotation(null, MixinConstants.AT); + AnnotationVisitor atAnn = atValue.visitAnnotation(null, MixinAnnotations.AT); atAnn.visit("value", "HEAD"); atAnn.visitEnd(); } @@ -90,14 +91,14 @@ private static void generateCancellerMethod(ClassNode generatedTarget, FieldNode } gen.newLabel(); gen.loadArg(0); - gen.invokeVirtual(MixinConstants.CI_TYPE, new Method("cancel", "()V")); + gen.invokeVirtual(TypeConstants.CI_TYPE, new Method("cancel", "()V")); } gen.visitLabel(endLabel); gen.returnValue(); gen.newLabel(); gen.endMethod(); // Modify mixin to set the field value - MethodQualifier qualifier = new MethodQualifier(MixinConstants.CI_TYPE.getDescriptor(), "cancel", "()V"); + MethodQualifier qualifier = new MethodQualifier(TypeConstants.CI_TYPE.getDescriptor(), "cancel", "()V"); InsnList methodInsns = context.methodNode().instructions; for (AbstractInsnNode insn : methodInsns) { if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java index 4d337b1b..2a5e3ac8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java @@ -14,7 +14,7 @@ import org.sinytra.adapter.patch.analysis.InstructionMatcher; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; import java.util.ArrayList; @@ -41,7 +41,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { // TODO Move to processor if (recipe.clean().isCancellable()) { - SplitMethodCancellationHelper.handle(this, context, recipe, method); + SplitMethodCancellationHelper.handle(context, recipe, method); } return MutableConfiguration.create() @@ -73,7 +73,7 @@ private static List locateCandidates(MixinContext context, Targ if (candidates.isEmpty()) { List nestedLambdas = invocations.stream() .flatMap(m -> MethodAnalyzer.findLambdasInMethod(dirtyTarget.classNode(), m, null).stream()) - .flatMap(s -> MethodQualifier.create(s).stream()) + .flatMap(s -> MethodQualifier.parse(s).stream()) .map(s -> context.methods().findOwnMethodPair(context.dirtyLookup(), s)) .filter(Objects::nonNull) .toList(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java index b5e17db1..c083e419 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java @@ -4,7 +4,7 @@ import org.sinytra.adapter.next.pipeline.Recipe; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.util.MethodQualifier; public class TargetMethodResolver extends CompoundResolver { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java index 90ab60ef..8b374651 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java +++ b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java @@ -14,7 +14,7 @@ import org.sinytra.adapter.next.pipeline.resolver.Resolver; import org.sinytra.adapter.next.pipeline.resolver.SubResolver; import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.TargetPair; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -62,7 +62,7 @@ public class TargetMethodSubResolvers { for (AbstractInsnNode insn : target.methodNode().instructions) { // Find lambda invocations and search for target insns inside the lambda if (insn instanceof InvokeDynamicInsnNode indy && indy.bsmArgs.length > 1 && indy.bsmArgs[1] instanceof Handle handle) { - TargetPair lambda = MethodQualifier.create(handle.getName()) + TargetPair lambda = MethodQualifier.parse(handle.getName()) .map(q -> context.methods().findOwnMethodPair(context.dirtyLookup(), q)) .orElse(null); if (lambda == null) return null; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java index 2f7f1ee4..9c51fed3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java @@ -2,8 +2,8 @@ import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchContext; +import org.sinytra.adapter.next.env.ctx.PatchResult; public interface ClassTransformer { PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java index 8b53ba01..25fcaac1 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java @@ -2,7 +2,7 @@ import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; public interface MethodTransformer { PatchResult apply(MixinContext context, Configuration config); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java index 23ac8d87..6ab69f12 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java @@ -6,11 +6,11 @@ import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.type.MixinTypes; +import org.sinytra.adapter.next.mixin.MixinTypes; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchContext; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -38,7 +38,7 @@ public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchCont } // FIXME Cannot use remap here! - MethodQualifier cleanOuterMethod = MethodQualifier.create(context.remap(cleanClass.outerMethod + cleanClass.outerMethodDesc)).orElse(null); + MethodQualifier cleanOuterMethod = MethodQualifier.parse(context.remap(cleanClass.outerMethod + cleanClass.outerMethodDesc)).orElse(null); if (cleanOuterMethod == null) { return PatchResult.PASS; } @@ -72,7 +72,7 @@ private static void stripOwnerFromMixinTargets(ClassNode classNode, PatchContext List mapped = val.get().stream() .map(target -> { String remapped = context.remap(target); - MethodQualifier q = MethodQualifier.create(remapped).orElse(null); + MethodQualifier q = MethodQualifier.parse(remapped).orElse(null); return q == null ? target : "L" + newOwner + ";" + q.name() + q.desc(); }) .toList(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java index 2a59cbd4..d2c7c81b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java @@ -5,8 +5,10 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; import org.sinytra.adapter.next.env.ann.ClassTarget; +import org.sinytra.adapter.next.env.ctx.PatchContext; +import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.patch.api.*; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.Collection; @@ -36,7 +38,7 @@ public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchCont for (FieldNode field : classNode.fields) { if (field.visibleAnnotations != null) { for (AnnotationNode ann : field.visibleAnnotations) { - if (MixinConstants.SHADOW.equals(ann.desc)) { + if (MixinAnnotations.SHADOW.equals(ann.desc)) { Collection targetFields = fields.get(field.desc); if (targetFields.size() == 1) { FieldNode targetField = targetFields.iterator().next(); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InjectParameterTransform.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/InjectParameterTransform.java similarity index 84% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InjectParameterTransform.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/InjectParameterTransform.java index 08d069b6..a624b934 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InjectParameterTransform.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/InjectParameterTransform.java @@ -1,31 +1,34 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.TypeReference; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.*; +import org.sinytra.adapter.next.env.ctx.PatchResult; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil.calculateLVTIndex; +import static org.sinytra.adapter.next.transform.param.ParamTransformationUtil.calculateLVTIndex; +// TODO Cleanup param transformers public record InjectParameterTransform(int index, Type type) implements ParameterTransformer { @Override - public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { boolean isNonStatic = (methodNode.access & Opcodes.ACC_STATIC) == 0; final int index = this.index + offset; if (index >= parameters.size() + 1) { return PatchResult.PASS; } - AnnotationHandle annotation = methodContext.methodAnnotation(); + AnnotationHandle annotation = context.methodAnnotation(); - if (annotation.matchesDesc(MixinConstants.MODIFY_VAR)) { + if (annotation.matchesDesc(MixinAnnotations.MODIFY_VAR)) { annotation.getValue("index").ifPresent(indexHandle -> { int indexValue = indexHandle.get(); if (indexValue >= index) { @@ -35,7 +38,7 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodConte return PatchResult.APPLY; } - if (annotation.matchesDesc(MixinConstants.MODIFY_ARGS)) { + if (annotation.matchesDesc(MixinAnnotations.MODIFY_ARGS)) { ModifyArgsOffsetUpgrader.upgradeAfterParamInsert(methodNode, this.index); return PatchResult.APPLY; } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InlineParameterTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/InlineParameterTransformer.java similarity index 83% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InlineParameterTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/InlineParameterTransformer.java index 1849acf5..e416f42c 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/InlineParameterTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/InlineParameterTransformer.java @@ -1,13 +1,12 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; @@ -21,7 +20,7 @@ public record InlineParameterTransformer(int target, Consumer parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { final int index = this.target + offset; LOGGER.info(MIXINPATCH, "Inlining parameter {} of method {}.{}", index, classNode.name, methodNode.name); final int replaceIndex = -999 + index; @@ -32,7 +31,7 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodConte } methodNode.localVariables.sort(Comparator.comparingInt(lvn -> lvn.index)); - LocalVariableNode lvn = methodNode.localVariables.remove(index + (methodContext.isStatic() ? 0 : 1)); + LocalVariableNode lvn = methodNode.localVariables.remove(index + (context.isStatic() ? 0 : 1)); AdapterUtil.replaceLVT(methodNode, idx -> idx == lvn.index ? replaceIndex : idx); }); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ModifyArgsOffsetUpgrader.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ModifyArgsOffsetUpgrader.java similarity index 96% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ModifyArgsOffsetUpgrader.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/ModifyArgsOffsetUpgrader.java index 0c0ed17e..9534265f 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ModifyArgsOffsetUpgrader.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ModifyArgsOffsetUpgrader.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/MoveParametersTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/MoveParametersTransformer.java similarity index 86% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/MoveParametersTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/MoveParametersTransformer.java index 0ae78684..c4ad6154 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/MoveParametersTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/MoveParametersTransformer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; @@ -6,11 +6,10 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.ParameterNode; +import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; @@ -22,7 +21,7 @@ public record MoveParametersTransformer(int from, int to) implements ParameterTr private static final Logger LOGGER = LogUtils.getLogger(); @Override - public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { final int paramIndex = this.from + offset; LOGGER.info(MIXINPATCH, "Moving parameter from index {} to {} in method {}.{}", this.from, this.to, classNode.name, methodNode.name); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformationUtil.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParamTransformationUtil.java similarity index 84% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformationUtil.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/ParamTransformationUtil.java index 6f261224..fdb0514a 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ParamTransformationUtil.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParamTransformationUtil.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; @@ -6,9 +6,8 @@ import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.MixinConstants; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.MethodQualifier; @@ -26,8 +25,8 @@ public static int calculateLVTIndex(List parameters, boolean nonStatic, in return lvt; } - public static List findWrapOperationOriginalCall(MethodNode methodNode, MethodContext methodContext) { - if (methodContext.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { + public static List findWrapOperationOriginalCall(MethodNode methodNode, MixinContext context) { + if (context.methodAnnotation().matchesDesc(MixinAnnotations.WRAP_OPERATION)) { List list = new ArrayList<>(); outer: for (AbstractInsnNode insn : methodNode.instructions) { @@ -48,7 +47,7 @@ public static List findWrapOperationOriginalCall(MethodNode me } public static List findWrapOperationOriginalCallArgs(MethodNode methodNode, MixinContext context) { - if (context.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { + if (context.methodAnnotation().matchesDesc(MixinAnnotations.WRAP_OPERATION)) { for (AbstractInsnNode insn : methodNode.instructions) { if (insn instanceof MethodInsnNode minsn && WO_ORIGINAL_CALL.matches(minsn)) { return MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParameterTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParameterTransformer.java new file mode 100644 index 00000000..4fae60ce --- /dev/null +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParameterTransformer.java @@ -0,0 +1,13 @@ +package org.sinytra.adapter.next.transform.param; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.PatchResult; + +import java.util.List; + +public interface ParameterTransformer { + PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset); +} diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/RemoveParameterTransformer.java similarity index 81% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/RemoveParameterTransformer.java index 6f9d8f83..37d2b305 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/RemoveParameterTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/RemoveParameterTransformer.java @@ -1,13 +1,12 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.List; @@ -18,9 +17,9 @@ public RemoveParameterTransformer(int index) { } @Override - public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { final int target = this.index() + offset; - final int lvtIndex = ParamTransformationUtil.calculateLVTIndex(parameters, !methodContext.isStatic(), target); + final int lvtIndex = ParamTransformationUtil.calculateLVTIndex(parameters, !context.isStatic(), target); LVTSnapshot.with(methodNode, () -> { LocalVariableNode lvn = methodNode.localVariables.stream() diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ReplaceParametersTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ReplaceParametersTransformer.java similarity index 85% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ReplaceParametersTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/ReplaceParametersTransformer.java index 5a486072..e66d8918 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/ReplaceParametersTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/ReplaceParametersTransformer.java @@ -1,21 +1,23 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.next.env.param.Parameters; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.api.*; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; -import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.next.types.BytecodeFixerUpper; +import org.sinytra.adapter.next.types.TypeAdapter; import org.slf4j.Logger; import java.util.List; +import static org.sinytra.adapter.next.transform.param.ParamTransformationUtil.findWrapOperationOriginalCall; import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; -import static org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil.findWrapOperationOriginalCall; // TODO Just add @Coerce if the types are inherited public record ReplaceParametersTransformer(int index, Type type, boolean upgradeUsage) implements ParameterTransformer { @@ -26,7 +28,7 @@ public ReplaceParametersTransformer(int index, Type type) { } @Override - public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { final int paramIndex = this.index + offset; if (methodNode.parameters.size() <= paramIndex) { @@ -42,7 +44,7 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodConte localVar.desc = this.type.getDescriptor(); localVar.signature = null; - List ignoreInsns = findWrapOperationOriginalCall(methodNode, methodContext); + List ignoreInsns = findWrapOperationOriginalCall(methodNode, context); BytecodeFixerUpper bfu = context.environment().bytecodeFixerUpper(); if (this.upgradeUsage && this.type.getSort() == Type.OBJECT && originalType.getSort() == Type.OBJECT) { // Replace variable usages with the new type @@ -57,7 +59,7 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodConte if (bfu != null && nextOp != Opcodes.IFNULL && nextOp != Opcodes.IFNONNULL) { TypeAdapter typeFix = bfu.getTypeAdapter(type, originalType); // If this is a wrap operation, make an educated guess and try adapting the instance type - if (typeFix == null && methodContext.methodAnnotation().matchesDesc(MixinConstants.WRAP_OPERATION)) { + if (typeFix == null && context.methodAnnotation().matchesDesc(MixinAnnotations.WRAP_OPERATION)) { List params = Parameters.getParameterTypes(methodNode.desc); if (!params.isEmpty()) { typeFix = bfu.getTypeAdapter(params.getFirst(), originalType); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SubstituteParameterTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/SubstituteParameterTransformer.java similarity index 59% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SubstituteParameterTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/SubstituteParameterTransformer.java index 0d852adc..c64a927d 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SubstituteParameterTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/SubstituteParameterTransformer.java @@ -1,29 +1,28 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; import java.util.List; -import static org.sinytra.adapter.patch.transformer.operation.param.ParamTransformationUtil.calculateLVTIndex; +import static org.sinytra.adapter.next.transform.param.ParamTransformationUtil.calculateLVTIndex; public record SubstituteParameterTransformer(int target, int substitute) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); @Override - public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { - final int paramIndex = this.target + offset; - final int substituteParamIndex = this.substitute + offset; - final boolean isNonStatic = !methodContext.isStatic(); - final int localIndex = calculateLVTIndex(parameters, isNonStatic, paramIndex); + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { + int paramIndex = this.target + offset; + int substituteParamIndex = this.substitute + offset; + boolean isNonStatic = !context.isStatic(); + int localIndex = calculateLVTIndex(parameters, isNonStatic, paramIndex); if (methodNode.parameters.size() <= paramIndex) { return PatchResult.PASS; @@ -35,7 +34,7 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodConte methodNode.parameters.remove(paramIndex); methodNode.localVariables.removeIf(lvn -> lvn.index == localIndex); - final int substituteIndex = calculateLVTIndex(parameters, isNonStatic, substituteParamIndex); + int substituteIndex = calculateLVTIndex(parameters, isNonStatic, substituteParamIndex); AdapterUtil.replaceLVT(methodNode, idx -> idx == localIndex ? substituteIndex : idx); }); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SwapParametersTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/SwapParametersTransformer.java similarity index 87% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SwapParametersTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/SwapParametersTransformer.java index c946bd7e..d319bc06 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/SwapParametersTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/SwapParametersTransformer.java @@ -1,11 +1,10 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.SingleValueHandle; import org.slf4j.Logger; @@ -19,10 +18,10 @@ public record SwapParametersTransformer(int from, int to) implements ParameterTr private static final Logger LOGGER = LogUtils.getLogger(); @Override - public PatchResult apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context, List parameters, int offset) { + public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { int from = offset + this.from; int to = offset + this.to; - boolean nonStatic = !methodContext.isStatic(); + boolean nonStatic = !context.isStatic(); ParameterNode fromNode = methodNode.parameters.get(from); ParameterNode toNode = methodNode.parameters.get(to); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/TransformParameters.java b/definition/src/next/java/org/sinytra/adapter/next/transform/param/TransformParameters.java similarity index 75% rename from definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/TransformParameters.java rename to definition/src/next/java/org/sinytra/adapter/next/transform/param/TransformParameters.java index 22f68fa3..bf37c856 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/transformer/operation/param/TransformParameters.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/param/TransformParameters.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.transformer.operation.param; +package org.sinytra.adapter.next.transform.param; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; @@ -7,11 +7,10 @@ import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import java.util.ArrayList; import java.util.Arrays; @@ -21,32 +20,38 @@ public record TransformParameters(List transformers, boolean withOffset) { // TODO - public PatchResult apply(MethodContext methodContext) { - ClassNode classNode = methodContext.getMixinClass(); - MethodNode methodNode = methodContext.getMixinMethod(); - PatchContext context = methodContext.patchContext(); - + public PatchResult apply(MixinContext context) { + ClassNode classNode = context.classNode(); + MethodNode methodNode = context.methodNode(); + Type[] params = Type.getArgumentTypes(methodNode.desc); List newParameterTypes = new ArrayList<>(Arrays.asList(params)); PatchResult result = PatchResult.PASS; - int offset = calculateOffset(methodContext); + int offset = calculateOffset(context); for (ParameterTransformer transform : transformers) { - result = result.or(transform.apply(classNode, methodNode, methodContext, context, newParameterTypes, offset)); + result = result.or(transform.apply(classNode, methodNode, context, newParameterTypes, offset)); } if (result != PatchResult.PASS) { - methodContext.updateDescription(newParameterTypes); + updateDescription(methodNode, newParameterTypes); } return result; } - private int calculateOffset(MethodContext methodContext) { - AnnotationHandle annotation = methodContext.methodAnnotation(); + private void updateDescription(MethodNode methodNode, List parameters) { + Type returnType = Type.getReturnType(methodNode.desc); + // recordAudit(transform, "Change descriptor to %s", newDesc); + methodNode.desc = Type.getMethodDescriptor(returnType, parameters.toArray(Type[]::new)); + methodNode.signature = null; + } + + private int calculateOffset(MixinContext context) { + AnnotationHandle annotation = context.methodAnnotation(); // If it's a redirect, the first local variable (index 1) is the object instance - boolean needsLocalOffset = annotation.matchesDesc(MixinConstants.REDIRECT) || annotation.matchesDesc(MixinConstants.WRAP_OPERATION); - return !methodContext.isStatic() && this.withOffset && needsLocalOffset ? 1 : 0; + boolean needsLocalOffset = annotation.matchesDesc(MixinAnnotations.REDIRECT) || annotation.matchesDesc(MixinAnnotations.WRAP_OPERATION); + return !context.isStatic() && this.withOffset && needsLocalOffset ? 1 : 0; } public static Builder builder() { diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java index 3c109670..d7fa3681 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java @@ -41,7 +41,7 @@ public MethodPatchBuilder targetClass(String... targets) { @Override public MethodPatchBuilder targetMethod(String... targets) { Stream.of(targets) - .map(t -> MethodQualifier.create(t).orElseThrow()) + .map(t -> MethodQualifier.parse(t).orElseThrow()) .forEach(t -> this.matcher.match(TARGET_METHOD, q -> q.matches(t))); return this; } @@ -82,7 +82,7 @@ public MethodPatchBuilder extractMixin(String targetClass) { @Override public MethodPatchBuilder modifyTarget(String method) { - MethodQualifier qualifier = MethodQualifier.create(method).orElseThrow(); + MethodQualifier qualifier = MethodQualifier.parse(method).orElseThrow(); this.config.setTargetMethod(qualifier); return this; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java index 6d1eec91..8366cdd0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java @@ -9,7 +9,7 @@ import org.sinytra.adapter.next.pipeline.processor.Processors; import org.sinytra.adapter.next.pipeline.resolver.Resolvers; import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchResult; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java b/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java deleted file mode 100644 index 4958b4f5..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/CapturedLocalsPreProcessor.java +++ /dev/null @@ -1,263 +0,0 @@ -package org.sinytra.adapter.next.transform.preprocess; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ListMultimap; -import com.mojang.datafixers.util.Pair; -import com.mojang.logging.LogUtils; -import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap; -import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.VisibleForTesting; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; -import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; -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.transformer.operation.param.TransformParameters; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.slf4j.Logger; -import org.spongepowered.asm.mixin.FabricUtil; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; - -// TODO This entire thing should be ditched for the Upgrade transformer using @Local -// And there will be no more rearrangement nonsense -@Deprecated -public class CapturedLocalsPreProcessor implements MethodTransformer { - private static final Logger LOGGER = LogUtils.getLogger(); - private static final Set ANNOTATIONS = Set.of(MixinConstants.INJECT, MixinConstants.MODIFY_EXPR_VAL, MixinConstants.MODIFY_VAR); - - @Override - public PatchResult apply(MixinContext context, Configuration config) { - ClassNode classNode = context.classNode(); - MethodNode methodNode = context.methodNode(); - MethodContext methodContext = context.legacy(); - - AnnotationHandle annotation = methodContext.methodAnnotation(); - if (methodNode.invisibleParameterAnnotations != null) { - // Find @Local annotations on method parameters - Type[] paramTypes = Type.getArgumentTypes(methodNode.desc); - List> localAnnotations = AdapterUtil.getAnnotatedParameters(methodNode, paramTypes, MixinConstants.LOCAL, Pair::of); - if (!localAnnotations.isEmpty()) { - PatchResult result = PatchResult.PASS; - for (Pair pair : localAnnotations) { - result = result.or(offsetParameterIndex(new AnnotationHandle(pair.getFirst()), pair.getSecond(), methodContext)); - } - return result; - } - } - if (!ANNOTATIONS.contains(annotation.getDesc())) { - return PatchResult.PASS; - } - if (annotation.matchesDesc(MixinConstants.MODIFY_VAR)) { - AnnotationValueHandle ordinal = annotation.getValue("ordinal").orElse(null); - if (ordinal == null && annotation.getValue("name").isEmpty()) { - Type[] args = Type.getArgumentTypes(methodNode.desc); - if (args.length < 1) { - return PatchResult.PASS; - } - TargetPair targetPair = methodContext.findDirtyInjectionTarget(); - if (targetPair == null) { - return PatchResult.PASS; - } - for (Integer level : methodContext.getLvtCompatLevelsOrdered()) { - List available = methodContext.getTargetMethodLocals(targetPair, 0, level); - if (available == null) { - return PatchResult.PASS; - } - Type expected = args[0]; - int count = (int) available.stream().filter(lv -> lv.type().equals(expected)).count(); - if (count == 1) { - annotation.appendValue("ordinal", 0); - return PatchResult.APPLY; - } - } - } - return PatchResult.PASS; - } - // Check if the mixin captures LVT - if (annotation.matchesDesc(MixinConstants.INJECT) && annotation.getValue("locals").isPresent()) { - ParamsDiffSnapshot diff = compareParameters(classNode, methodNode, methodContext); - if (diff != null) { - // Apply parameter patch - TransformParameters transform = diff.asParameterTransformer(true); - return transform.apply(); - } - } - return PatchResult.PASS; - } - - private PatchResult offsetParameterIndex(AnnotationHandle annotation, Type paramType, MethodContext methodContext) { - // Validate implicit targets for @Local parameters - if (annotation.getAllValues().isEmpty()) { - int compatLevel = methodContext.patchContext().environment().fabricLVTCompatibility(); - if (compatLevel != FabricUtil.COMPATIBILITY_0_10_0) { - return PatchResult.PASS; - } - TargetPair targetPair = methodContext.findDirtyInjectionTarget(); - if (targetPair == null) { - return PatchResult.PASS; - } - List locals = methodContext.getTargetMethodLocals(targetPair, 0, compatLevel); - if (locals != null && locals.stream().filter(var -> var.type() == paramType).count() > 1) { - // Mixin found more locals than required, let's try to fix this - // The old method might still get us the expected results - List oldCompatLocals = methodContext.getTargetMethodLocals(targetPair, 0, FabricUtil.COMPATIBILITY_0_9_2); - List sameType = oldCompatLocals.stream().filter(var -> var.type() == paramType).toList(); - if (sameType.size() == 1) { - int index = sameType.getFirst().index(); - annotation.appendValue("index", index); - methodContext.recordAudit(this, "Fix @Local annotation using index %s", index); - return PatchResult.APPLY; - } - } - } - return PatchResult.PASS; - } - - @Nullable - private ParamsDiffSnapshot compareParameters(ClassNode classNode, MethodNode methodNode, MethodContext methodContext) { - LocalVarAnalyzer.CapturedLocalsInfo info = LocalVarAnalyzer.getCapturedLocals(methodContext); - if (info == null) { - return null; - } - ParamsDiffSnapshot diff = info.diff(); - if (diff.isEmpty()) { - 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 - LayeredParamsDiffSnapshot rearrange = CapturedLocalsPreProcessor.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 = rearrange; - } - - int paramLocalStart = capturedLocals.paramLocalStart(); - if (!diff.removals().isEmpty()) { - List lvt = methodNode.localVariables.stream().sorted(Comparator.comparingInt(lvn -> lvn.index)).toList(); - for (int removal : diff.removals()) { - int removalLocal = removal + capturedLocals.lvtOffset() + paramLocalStart; - if (removalLocal >= lvt.size()) { - continue; - } - int removalIndex = lvt.get(removalLocal).index; - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof VarInsnNode varInsn && varInsn.var == removalIndex) { - LOGGER.debug(MIXINPATCH, "Cannot remove parameter {} in mixin method {}.{}", removal, classNode.name, methodNode.name + methodNode.desc); - return null; - } - } - } - } - // Offset the insertion to the correct parameter indices - // Also remove any appended variables - int maxInsert = getMaxLocalIndex(capturedLocals.expected(), diff.insertions()); - ParamsDiffSnapshot offsetDiff = diff.offset(paramLocalStart, maxInsert); - if (offsetDiff.isEmpty()) { - // No changes required - return null; - } - return offsetDiff; - } - - private static boolean areReplacedParamsUsed(List> replacements, MethodNode methodNode) { - LocalVariableLookup lookup = new LocalVariableLookup(methodNode); - Set 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 expected, List> insertions) { - int maxIndex = expected.size(); - for (Pair pair : insertions) { - int at = pair.getFirst(); - if (at < maxIndex) { - maxIndex++; - } - } - return maxIndex; - } - - @VisibleForTesting - @Nullable - public static LayeredParamsDiffSnapshot rearrangeParameters(List parameterTypes, List newParameterTypes) { - Object2IntMap typeCount = new Object2IntOpenHashMap<>(); - ListMultimap typeIndices = ArrayListMultimap.create(); - for (int i = 0; i < parameterTypes.size(); i++) { - Type type = parameterTypes.get(i); - typeCount.put(type, typeCount.getInt(type) + 1); - typeIndices.put(type, i); - } - Object2IntMap newTypeCount = new Object2IntOpenHashMap<>(); - for (Type type : newParameterTypes) { - newTypeCount.put(type, newTypeCount.getInt(type) + 1); - } - - for (Object2IntMap.Entry entry : typeCount.object2IntEntrySet()) { - if (newTypeCount.getInt(entry.getKey()) != entry.getIntValue()) { - return null; - } - } - - List> insertions = new ArrayList<>(); - for (int i = 0; i < newParameterTypes.size(); i++) { - Type type = newParameterTypes.get(i); - if (!typeCount.containsKey(type)) { - insertions.add(Pair.of(i, type)); - } - } - - Object2IntMap seenTypes = new Object2IntOpenHashMap<>(); - Int2IntMap swaps = new Int2IntLinkedOpenHashMap(); - for (int i = 0; i < newParameterTypes.size(); i++) { - Type type = newParameterTypes.get(i); - if (typeIndices.containsKey(type)) { - List indices = typeIndices.get(type); - int seen = seenTypes.getInt(type); - int oldIndex = indices.get(seen); - seenTypes.put(type, seen + 1); - if (oldIndex != i && !swaps.containsKey(i)) { - swaps.put(oldIndex, i); - } - } - } - - if (swaps.isEmpty()) { - return null; - } - - List> swapsList = new ArrayList<>(); - swaps.forEach((from, to) -> swapsList.add(Pair.of(from, to))); - - return LayeredParamsDiffSnapshot.builder() - .insertions(insertions) - .swaps(swapsList) - .build(); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java index 0e9d28fb..a9f35a00 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java @@ -6,14 +6,14 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.ctx.AuditTrail; +import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.config.Configuration; import org.sinytra.adapter.next.pipeline.config.Keys; import org.sinytra.adapter.next.transform.MethodTransformer; import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchAuditTrail; -import org.sinytra.adapter.patch.api.PatchResult; -import org.sinytra.adapter.patch.api.TargetPair; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import java.util.ArrayList; @@ -34,39 +34,34 @@ public PatchResult apply(MixinContext context, Configuration config) { // Analyze locals MethodNode methodNode = context.methodNode(); Type[] paramTypes = Type.getArgumentTypes(methodNode.desc); - List> localAnnotations = AdapterUtil.getAnnotatedParameters(methodNode, paramTypes, MixinConstants.LOCAL, Pair::of); - if (!localAnnotations.isEmpty()) { - return PatchResult.PASS; - } + List> localAnnotations = AdapterUtil.getAnnotatedParameters(methodNode, paramTypes, MixinAnnotations.LOCAL, Pair::of); + if (!localAnnotations.isEmpty()) return PatchResult.PASS; - LocalVarAnalyzer.CapturedLocalsInfo info = LocalVarAnalyzer.getCapturedLocals(context.legacy()); - if (info == null || info.diff().isEmpty()) { - return PatchResult.PASS; - } + LocalVarAnalyzer.CapturedLocalsInfo info = LocalVarAnalyzer.getCapturedLocals(context, dirtyTarget); + if (info == null || info.diff().isEmpty()) return PatchResult.PASS; 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 PatchResult.PASS; - } + if (available.size() != 1) return PatchResult.PASS; + availableTypes.remove(available.getFirst()); } - PatchResult result = transform.remover().apply(context.legacy()); + PatchResult result = transform.remover().apply(context); if (result == PatchResult.PASS) return PatchResult.PASS; int start = info.capturedLocals().paramLocalStart(); Type[] args = Type.getArgumentTypes(methodNode.desc); for (int i = start; i < args.length; i++) { - methodNode.visitParameterAnnotation(i, MixinConstants.LOCAL, false); + methodNode.visitParameterAnnotation(i, MixinAnnotations.LOCAL, false); } - PatchAuditTrail auditTrail = context.environment().auditTrail(); + AuditTrail auditTrail = context.environment().auditTrail(); // auditTrail.recordAudit(this, methodContext, "Upgrade captured locals"); - auditTrail.recordResult(context.legacy(), PatchAuditTrail.Match.FULL); + auditTrail.recordResult(context, config, AuditTrail.Match.FULL); return result; } } diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/BytecodeFixerJarGenerator.java b/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerJarGenerator.java similarity index 99% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/BytecodeFixerJarGenerator.java rename to definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerJarGenerator.java index d3b6c986..692dca2e 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/BytecodeFixerJarGenerator.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerJarGenerator.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/BytecodeFixerUpper.java b/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerUpper.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/BytecodeFixerUpper.java rename to definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerUpper.java index badc61be..851671a8 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/BytecodeFixerUpper.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerUpper.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.Nullable; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/FieldAccessorTypeTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/types/FieldAccessorTypeTransformer.java similarity index 91% rename from definition/src/next/java/org/sinytra/adapter/next/transform/FieldAccessorTypeTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/types/FieldAccessorTypeTransformer.java index fc6d9755..a1f43324 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/FieldAccessorTypeTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/FieldAccessorTypeTransformer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.transform; +package org.sinytra.adapter.next.types; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.AnnotationVisitor; @@ -7,13 +7,11 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.next.env.MixinContext; +import org.sinytra.adapter.next.env.util.MixinAnnotations; import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.next.transform.MethodTransformer; import org.sinytra.adapter.patch.analysis.selector.FieldMatcher; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.PatchResult; -import org.sinytra.adapter.patch.fixes.BytecodeFixerJarGenerator; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; -import org.sinytra.adapter.patch.fixes.TypeAdapter; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; // TODO Clean up maybe @@ -41,7 +39,7 @@ public PatchResult apply(MixinContext context, Configuration config) { String targetMethod = addRedirectAcceptorField(owner, methodNode, fieldName, typeAdapter, bfu.getGenerator()); methodNode.visibleAnnotations.remove(context.methodAnnotation().unwrap()); - AnnotationVisitor invokerAnn = methodNode.visitAnnotation(MixinConstants.INVOKER, true); + AnnotationVisitor invokerAnn = methodNode.visitAnnotation(MixinAnnotations.INVOKER, true); invokerAnn.visit("value", targetMethod); return PatchResult.APPLY; } @@ -60,7 +58,7 @@ private String addRedirectAcceptorField(Type owner, MethodNode methodNode, Strin boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC; MethodNode method = (MethodNode) node.visitMethod(Opcodes.ACC_PUBLIC | (isStatic ? Opcodes.ACC_STATIC : 0), methodName, methodDesc, null, null); { - AnnotationVisitor annotationVisitor = method.visitAnnotation(MixinConstants.UNIQUE, true); + AnnotationVisitor annotationVisitor = method.visitAnnotation(MixinAnnotations.UNIQUE, true); annotationVisitor.visitEnd(); } { @@ -89,7 +87,7 @@ private ClassNode generateFieldAdapterMixin(String className, Type targetClass) node.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, className, null, "java/lang/Object", null); { - AnnotationVisitor mixinAnnotation = node.visitAnnotation(MixinConstants.MIXIN, false); + AnnotationVisitor mixinAnnotation = node.visitAnnotation(MixinAnnotations.MIXIN, false); { AnnotationVisitor valueVisitor = mixinAnnotation.visitArray("value"); valueVisitor.visit(null, targetClass); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/types/FieldTypeUsageTransformer.java similarity index 97% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java rename to definition/src/next/java/org/sinytra/adapter/next/types/FieldTypeUsageTransformer.java index 8f26b015..95e01376 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/FieldTypeUsageTransformer.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/FieldTypeUsageTransformer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; @@ -8,8 +8,8 @@ import org.sinytra.adapter.next.env.ann.ClassTarget; import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchResult; +import org.sinytra.adapter.next.env.ctx.PatchContext; +import org.sinytra.adapter.next.env.ctx.PatchResult; import org.sinytra.adapter.patch.util.AdapterUtil; import org.slf4j.Logger; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/ObjectTypeAdapter.java b/definition/src/next/java/org/sinytra/adapter/next/types/ObjectTypeAdapter.java similarity index 96% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/ObjectTypeAdapter.java rename to definition/src/next/java/org/sinytra/adapter/next/types/ObjectTypeAdapter.java index 108b442a..24c10cb9 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/ObjectTypeAdapter.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/ObjectTypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/SimpleTypeAdapter.java b/definition/src/next/java/org/sinytra/adapter/next/types/SimpleTypeAdapter.java similarity index 94% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/SimpleTypeAdapter.java rename to definition/src/next/java/org/sinytra/adapter/next/types/SimpleTypeAdapter.java index 54815c7a..18ca0c31 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/SimpleTypeAdapter.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/SimpleTypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/SupplierTypeAdapter.java b/definition/src/next/java/org/sinytra/adapter/next/types/SupplierTypeAdapter.java similarity index 97% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/SupplierTypeAdapter.java rename to definition/src/next/java/org/sinytra/adapter/next/types/SupplierTypeAdapter.java index c634e943..7c3ef16a 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/SupplierTypeAdapter.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/SupplierTypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/TypeAdapter.java b/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapter.java similarity index 89% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/TypeAdapter.java rename to definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapter.java index 964ec1a1..c339c0e8 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/TypeAdapter.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/fixes/TypeAdapterProvider.java b/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapterProvider.java similarity index 74% rename from definition/src/main/java/org/sinytra/adapter/patch/fixes/TypeAdapterProvider.java rename to definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapterProvider.java index c257cf99..bb5cbcf5 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/fixes/TypeAdapterProvider.java +++ b/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapterProvider.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.fixes; +package org.sinytra.adapter.next.types; import org.objectweb.asm.Type; diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java index 95b3d4ff..7ee8bd95 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java @@ -4,17 +4,13 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.transform.preprocess.CapturedLocalsPreProcessor; import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; import org.sinytra.adapter.patch.analysis.params.ParametersDiff; import org.sinytra.adapter.patch.test.mixin.MinecraftMixinPatchTest; import java.io.IOException; -import java.util.Deque; import java.util.List; -import java.util.Map; -import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -143,28 +139,4 @@ public void testCompareRemovedParameters() { diff.removals().forEach(param -> System.out.println("AT " + param)); assertEquals(1, diff.removals().size()); } - - @Test - public void testCompareReorderedParameters() { - Type[] original = new Type[]{Type.getType(String.class), Type.getType(List.class), Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE, Type.getType(Set.class), Type.getType(Map.class)}; - Type[] modified = new Type[]{Type.getType(String.class), Type.getType(List.class), Type.getType(Deque.class), Type.getType(Map.class), Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE, Type.getType(Set.class)}; - - LayeredParamsDiffSnapshot diff = CapturedLocalsPreProcessor.rearrangeParameters(List.of(original), List.of(modified)); - - System.out.println("Insertions:"); - diff.insertions().forEach(param -> System.out.println("AT " + param.getFirst() + " TYPE " + param.getSecond())); - assertEquals(1, diff.insertions().size()); - - System.out.println("Replacements:"); - diff.replacements().forEach(param -> System.out.println("AT " + param.getFirst() + " TYPE " + param.getSecond())); - assertTrue(diff.replacements().isEmpty()); - - System.out.println("Swaps:"); - diff.swaps().forEach(param -> System.out.println("AT " + param.getFirst() + " TYPE " + param.getSecond())); - assertEquals(3, diff.swaps().size()); - - System.out.println("Removals:"); - diff.removals().forEach(param -> System.out.println("AT " + param)); - assertTrue(diff.removals().isEmpty()); - } } diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java index 0ddc9f29..f227e1d2 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java @@ -6,9 +6,9 @@ import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.TypeInsnNode; -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.next.types.BytecodeFixerUpper; +import org.sinytra.adapter.next.types.SimpleTypeAdapter; +import org.sinytra.adapter.next.types.TypeAdapter; import org.sinytra.adapter.patch.util.provider.ClassLookup; import java.util.List; 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 1e01946f..f4dc3c7a 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 @@ -7,9 +7,9 @@ import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.next.flow.DynamicPatches; import org.sinytra.adapter.next.flow.Patcher; -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.next.env.ctx.PatchEnvironment; +import org.sinytra.adapter.next.env.ctx.RefmapHolder; +import org.sinytra.adapter.next.types.FieldTypeUsageTransformer; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.slf4j.Logger; import org.spongepowered.asm.mixin.FabricUtil; @@ -45,8 +45,7 @@ public void copyEntries(String from, String to) { patcher = new Patcher( patchEnvironment, List.of(new FieldTypeUsageTransformer()), - DynamicPatches.methodTransformers(List.of()), - List.of() + DynamicPatches.methodTransformers(List.of()) ); } 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 1216a715..e18fa59d 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 @@ -6,11 +6,11 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.next.env.util.MixinAnnotations; 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.next.env.ctx.MixinClassGenerator; +import org.sinytra.adapter.next.env.ctx.PatchEnvironment; import org.sinytra.adapter.patch.util.AdapterUtil; import org.sinytra.adapter.patch.util.provider.ClassLookup; import org.sinytra.adapter.patch.util.provider.ZipClassLookup; @@ -189,9 +189,9 @@ protected static ClassLookup createDirtyLookup() { protected AssertCallback assertUnique() { return (patched, expected, env) -> { - Assertions.assertThat(patched.visibleAnnotations.stream().anyMatch(ann -> ann.desc.equals(MixinConstants.UNIQUE))) + Assertions.assertThat(patched.visibleAnnotations.stream().anyMatch(ann -> ann.desc.equals(MixinAnnotations.UNIQUE))) .as("Unique method") - .isEqualTo(expected.visibleAnnotations.stream().anyMatch(ann -> ann.desc.equals(MixinConstants.UNIQUE))); + .isEqualTo(expected.visibleAnnotations.stream().anyMatch(ann -> ann.desc.equals(MixinAnnotations.UNIQUE))); }; } From 4216d6e6730cd6601fd4fbef8b6f9e7421451b4c Mon Sep 17 00:00:00 2001 From: Su5eD Date: Mon, 26 Jan 2026 22:17:22 +0100 Subject: [PATCH 08/27] Rename definition to core --- .github/workflows/release.yml | 2 +- .gitignore | 2 +- {definition => core}/build.gradle.kts | 7 +-- {definition => core}/settings.gradle.kts | 2 +- .../adapter}/analysis/InheritanceHandler.java | 4 +- .../adapter}/analysis/InsnComparator.java | 2 +- .../adapter}/analysis/InstructionMatcher.java | 2 +- .../analysis/MethodLabelComparator.java | 6 +-- .../adapter}/analysis/locals/LVTSnapshot.java | 6 +-- .../analysis/locals/LocalVarAnalyzer.java | 18 ++++---- .../analysis/locals/LocalVariableLookup.java | 2 +- .../analysis/method/MethodAnalyzer.java | 10 ++-- .../analysis/method/MethodCallAnalyzer.java | 10 ++-- .../analysis/method/MethodInsnMatcher.java | 4 +- .../analysis/params/EnhancedParamsDiff.java | 6 +-- .../params/LayeredParamsDiffSnapshot.java | 5 +- .../analysis/params/ParametersDiff.java | 6 +-- .../analysis/params/ParamsDiffSnapshot.java | 4 +- .../params/ParamsDiffSnapshotBuilder.java | 2 +- .../analysis/selector/AnnotationHandle.java | 2 +- .../selector/AnnotationValueHandle.java | 2 +- .../analysis/selector/FieldMatcher.java | 2 +- .../adapter}/analysis/selector/FrameUtil.java | 2 +- .../sinytra/adapter}/env/MixinContext.java | 18 ++++---- .../adapter}/env/MockMixinRuntime.java | 6 +-- .../org/sinytra/adapter}/env/ann/AtData.java | 18 ++++---- .../sinytra/adapter}/env/ann/ClassTarget.java | 10 ++-- .../adapter}/env/ann/ConstantData.java | 6 +-- .../sinytra/adapter}/env/ann/SliceData.java | 12 ++--- .../sinytra/adapter}/env/ctx/AuditTrail.java | 6 +-- .../adapter}/env/ctx/AuditTrailImpl.java | 10 ++-- .../org/sinytra/adapter}/env/ctx/Auditor.java | 2 +- .../adapter}/env/ctx/LocalVariable.java | 2 +- .../adapter}/env/ctx/MethodFinder.java | 8 ++-- .../adapter}/env/ctx/MethodHelper.java | 28 +++++------ .../adapter}/env/ctx/MixinClassGenerator.java | 2 +- .../env/ctx/MixinClassGeneratorImpl.java | 4 +- .../adapter}/env/ctx/PatchContext.java | 2 +- .../adapter}/env/ctx/PatchContextImpl.java | 2 +- .../adapter}/env/ctx/PatchEnvironment.java | 8 ++-- .../env/ctx/PatchEnvironmentImpl.java | 10 ++-- .../sinytra/adapter}/env/ctx/PatchResult.java | 2 +- .../sinytra/adapter}/env/ctx/RefMapper.java | 2 +- .../adapter}/env/ctx/RefmapHolder.java | 2 +- .../sinytra/adapter}/env/ctx/TargetPair.java | 2 +- .../adapter}/env/param/Annotation.java | 2 +- .../sinytra/adapter}/env/param/Copiable.java | 2 +- .../adapter}/env/param/MethodParameters.java | 4 +- .../adapter}/env/param/ParamDiffResolver.java | 6 +-- .../sinytra/adapter}/env/param/Parameter.java | 4 +- .../adapter}/env/param/Parameters.java | 6 +-- .../env/util/MixinAnnotationConstants.java | 2 +- .../adapter}/env/util/MixinAnnotations.java | 2 +- .../adapter}/env/util/OrderedRegistry.java | 2 +- .../adapter}/env/util/TypeConstants.java | 2 +- .../env/util/WeighedDisambiguation.java | 4 +- .../sinytra/adapter/patch/DynamicPatches.java | 31 +++++++++++++ .../sinytra/adapter/patch}/MixinParser.java | 20 ++++---- .../org/sinytra/adapter/patch}/Patcher.java | 35 +++++++------- .../org/sinytra/adapter/patch}/Recipe.java | 16 +++---- .../org/sinytra/adapter/patch}/TxResult.java | 2 +- .../patch}/config/BasePropertyContainer.java | 8 ++-- .../adapter/patch}/config/Configuration.java | 8 ++-- .../patch}/config/ConfigurationImpl.java | 10 ++-- .../patch/config}/ConfigurationTemplates.java | 5 +- .../adapter/patch/config/Configurations.java | 6 +++ .../sinytra/adapter/patch}/config/Keys.java | 14 +++--- .../patch}/config/MutableConfiguration.java | 8 ++-- .../config/MutablePropertyContainer.java | 6 +-- .../patch}/config/PropertyContainer.java | 2 +- .../config/PropertyContainerTemplate.java | 2 +- .../adapter/patch}/config/PropertyKey.java | 4 +- .../adapter/patch}/config/SpecialKeys.java | 2 +- .../adapter/patch}/mixin/InjectMixin.java | 34 +++++++------- .../adapter/patch/mixin/MixinType.java | 21 +++++++++ .../adapter/patch}/mixin/MixinTypes.java | 4 +- .../adapter/patch}/mixin/ModifyArgMixin.java | 42 ++++++++--------- .../mixin/ModifyExpressionValueMixin.java | 36 +++++++-------- .../patch/mixin/ModifyReturnValueMixin.java | 32 +++++++++++++ .../patch}/mixin/ModifyVariableMixin.java | 44 +++++++++--------- .../adapter/patch}/mixin/RedirectMixin.java | 42 ++++++++--------- .../patch}/mixin/WrapOperationMixin.java | 44 +++++++++--------- .../processor/DisableMixinProcessor.java | 10 ++-- .../processor/InjectionTargetProcessor.java | 20 ++++---- .../patch}/processor/MixinTypeProcessor.java | 12 ++--- .../patch}/processor/ParametersProcessor.java | 20 ++++---- .../adapter/patch/processor/Processor.java | 10 ++++ .../adapter/patch}/processor/Processors.java | 6 +-- .../patch}/processor/PropertyProcessor.java | 16 +++---- .../patch}/processor/ReturnTypeProcessor.java | 16 +++---- .../processor/StaticAccessProcessor.java | 14 +++--- .../processor/TargetMethodProcessor.java | 18 ++++---- .../extract/ExtractMixinProcessor.java | 32 ++++++------- .../extract/MirrorableExtractMixin.java | 26 +++++------ .../redirect/DivertRedirectProcessor.java | 18 ++++---- .../redirect/ParameterUsageProcessor.java | 14 +++--- .../processor/wrapop/WrapOpAnalyzer.java | 6 +-- .../wrapop/WrapOpParamsProcessor.java | 24 +++++----- .../processor/wrapop/WrapOpSurgeon.java | 20 ++++---- .../patch}/resolver/CompoundResolver.java | 8 ++-- .../adapter/patch}/resolver/Resolver.java | 8 ++-- .../adapter/patch}/resolver/Resolvers.java | 10 ++-- .../adapter/patch/resolver/SubResolver.java | 11 +++++ .../ArbitraryInjectionPointSubResolver.java | 30 ++++++------ .../AtVariableAssignStoreSubResolver.java | 22 ++++----- .../ComparingInjectionPointResolver.java | 46 +++++++++---------- .../InheritedInjectionPointSubResolver.java | 36 +++++++-------- .../injection/InjectionPointResolver.java | 12 ++--- .../injection/InjectionPointSubResolvers.java | 26 +++++------ .../ModifyVarInjectionPointSubResolver.java | 22 ++++----- .../special/InjectorOrdinalResolver.java | 44 +++++++++--------- .../special/ModifyVarAtReturnResolver.java | 26 +++++------ .../special/ModifyVarUpgradeResolver.java | 18 ++++---- .../special/ResolverSyntheticInstanceof.java | 28 +++++------ .../special/SliceBoundaryResolver.java | 26 +++++------ .../target/SplitMethodCancellationHelper.java | 20 ++++---- .../target/SplitTargetMethodSubResolver.java | 24 +++++----- .../resolver/target/TargetMethodResolver.java | 14 +++--- .../target/TargetMethodSubResolvers.java | 22 ++++----- .../adapter/transform/ClassTransformer.java | 10 ++++ .../adapter/transform/MethodTransformer.java | 9 ++++ .../transform}/PipelineMethodTransformer.java | 37 +++++++-------- .../cls/DynamicAnonClassIndexPatch.java | 18 ++++---- .../DynamicAnonymousShadowFieldTypePatch.java | 14 +++--- .../param/InjectParameterTransform.java | 14 +++--- .../param/InlineParameterTransformer.java | 12 ++--- .../param/ModifyArgsOffsetUpgrader.java | 8 ++-- .../param/MoveParametersTransformer.java | 14 +++--- .../param/ParamTransformationUtil.java | 12 ++--- .../transform/param/ParameterTransformer.java | 6 +-- .../param/RemoveParameterTransformer.java | 10 ++-- .../param/ReplaceParametersTransformer.java | 22 ++++----- .../param/SubstituteParameterTransformer.java | 12 ++--- .../param/SwapParametersTransformer.java | 12 ++--- .../transform/param/TransformParameters.java | 10 ++-- .../transform/patch/ConfigurationMatcher.java | 6 +-- .../adapter}/transform/patch/MethodPatch.java | 6 +-- .../transform/patch/MethodPatchBuilder.java | 4 +- .../patch/MethodPatchBuilderImpl.java | 16 +++---- .../transform/patch/MethodPatchImpl.java | 6 +-- .../patch/MethodPatchTransformer.java | 23 +++++----- .../LocalCaptureUpgradeTransformer.java | 22 ++++----- .../types/BytecodeFixerJarGenerator.java | 2 +- .../adapter}/types/BytecodeFixerUpper.java | 4 +- .../types/FieldAccessorTypeTransformer.java | 16 +++---- .../types/FieldTypeUsageTransformer.java | 16 +++---- .../adapter}/types/ObjectTypeAdapter.java | 2 +- .../adapter}/types/SimpleTypeAdapter.java | 2 +- .../adapter}/types/SupplierTypeAdapter.java | 2 +- .../sinytra/adapter}/types/TypeAdapter.java | 2 +- .../adapter}/types/TypeAdapterProvider.java | 2 +- .../sinytra/adapter}/util/AdapterUtil.java | 22 ++++----- .../adapter}/util/GeneratedVariables.java | 2 +- .../adapter}/util/MethodQualifier.java | 2 +- .../org/sinytra/adapter}/util/OpcodeUtil.java | 2 +- .../adapter}/util/SingleValueHandle.java | 2 +- .../adapter}/util/provider/ClassLookup.java | 2 +- .../util/provider/MixinClassLookup.java | 2 +- .../util/provider/ZipClassLookup.java | 2 +- .../adapter/next/env/Configurations.java | 9 ---- .../adapter/next/flow/DynamicPatches.java | 31 ------------- .../sinytra/adapter/next/mixin/MixinType.java | 21 --------- .../next/mixin/ModifyReturnValueMixin.java | 32 ------------- .../next/pipeline/config/ConfigAttribute.java | 46 ------------------- .../next/pipeline/processor/Processor.java | 10 ---- .../next/pipeline/resolver/SubResolver.java | 11 ----- .../next/transform/ClassTransformer.java | 10 ---- .../next/transform/MethodTransformer.java | 9 ---- settings.gradle.kts | 2 +- test/build.gradle.kts | 6 +-- .../patch/test/EnhancedParamsDiffTest.java | 4 +- .../patch/test/ParamDiffResolverTest.java | 10 ++-- .../patch/test/ParameterComparisonTest.java | 6 +-- .../mixin/BytecodeFixerUpperTestFrontend.java | 10 ++-- .../test/mixin/DynamicMixinPatchTest.java | 12 ++--- .../test/mixin/MinecraftMixinPatchTest.java | 16 +++---- 176 files changed, 1047 insertions(+), 1104 deletions(-) rename {definition => core}/build.gradle.kts (93%) rename {definition => core}/settings.gradle.kts (94%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/InheritanceHandler.java (94%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/InsnComparator.java (99%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/InstructionMatcher.java (98%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/MethodLabelComparator.java (97%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/locals/LVTSnapshot.java (95%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/locals/LocalVarAnalyzer.java (92%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/locals/LocalVariableLookup.java (98%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/method/MethodAnalyzer.java (96%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/method/MethodCallAnalyzer.java (94%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/method/MethodInsnMatcher.java (96%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/params/EnhancedParamsDiff.java (99%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/params/LayeredParamsDiffSnapshot.java (98%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/params/ParametersDiff.java (97%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/params/ParamsDiffSnapshot.java (87%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/params/ParamsDiffSnapshotBuilder.java (96%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/selector/AnnotationHandle.java (98%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/selector/AnnotationValueHandle.java (98%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/selector/FieldMatcher.java (93%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/analysis/selector/FrameUtil.java (98%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/MixinContext.java (87%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/MockMixinRuntime.java (98%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ann/AtData.java (89%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ann/ClassTarget.java (85%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ann/ConstantData.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ann/SliceData.java (78%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/AuditTrail.java (93%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/AuditTrailImpl.java (96%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/Auditor.java (70%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/LocalVariable.java (67%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/MethodFinder.java (94%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/MethodHelper.java (92%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/MixinClassGenerator.java (90%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/MixinClassGeneratorImpl.java (96%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/PatchContext.java (92%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/PatchContextImpl.java (96%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/PatchEnvironment.java (82%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/PatchEnvironmentImpl.java (81%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/PatchResult.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/RefMapper.java (62%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/RefmapHolder.java (75%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/ctx/TargetPair.java (79%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/param/Annotation.java (98%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/param/Copiable.java (52%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/param/MethodParameters.java (98%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/param/ParamDiffResolver.java (94%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/param/Parameter.java (95%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/param/Parameters.java (96%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/util/MixinAnnotationConstants.java (95%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/util/MixinAnnotations.java (98%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/util/OrderedRegistry.java (98%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/util/TypeConstants.java (94%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/env/util/WeighedDisambiguation.java (95%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java rename {definition/src/next/java/org/sinytra/adapter/next/flow => core/src/main/java/org/sinytra/adapter/patch}/MixinParser.java (84%) rename {definition/src/next/java/org/sinytra/adapter/next/flow => core/src/main/java/org/sinytra/adapter/patch}/Patcher.java (79%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/Recipe.java (89%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/TxResult.java (62%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/BasePropertyContainer.java (94%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/Configuration.java (71%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/ConfigurationImpl.java (95%) rename {definition/src/next/java/org/sinytra/adapter/next/env => core/src/main/java/org/sinytra/adapter/patch/config}/ConfigurationTemplates.java (79%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/config/Configurations.java rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/Keys.java (90%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/MutableConfiguration.java (89%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/MutablePropertyContainer.java (85%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/PropertyContainer.java (85%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/PropertyContainerTemplate.java (97%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/PropertyKey.java (96%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/config/SpecialKeys.java (91%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter/patch}/mixin/InjectMixin.java (72%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter/patch}/mixin/MixinTypes.java (95%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter/patch}/mixin/ModifyArgMixin.java (70%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter/patch}/mixin/ModifyExpressionValueMixin.java (60%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter/patch}/mixin/ModifyVariableMixin.java (63%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter/patch}/mixin/RedirectMixin.java (64%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter/patch}/mixin/WrapOperationMixin.java (64%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/DisableMixinProcessor.java (64%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/InjectionTargetProcessor.java (68%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/MixinTypeProcessor.java (73%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/ParametersProcessor.java (80%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/Processors.java (74%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/PropertyProcessor.java (55%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/ReturnTypeProcessor.java (81%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/StaticAccessProcessor.java (85%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/TargetMethodProcessor.java (71%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/extract/ExtractMixinProcessor.java (94%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/extract/MirrorableExtractMixin.java (84%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/redirect/DivertRedirectProcessor.java (78%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/redirect/ParameterUsageProcessor.java (75%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/wrapop/WrapOpAnalyzer.java (95%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/wrapop/WrapOpParamsProcessor.java (90%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/processor/wrapop/WrapOpSurgeon.java (91%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/CompoundResolver.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/Resolver.java (83%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/Resolvers.java (54%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/injection/ArbitraryInjectionPointSubResolver.java (83%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/injection/AtVariableAssignStoreSubResolver.java (85%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/injection/ComparingInjectionPointResolver.java (89%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/injection/InheritedInjectionPointSubResolver.java (71%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/injection/InjectionPointResolver.java (73%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/injection/InjectionPointSubResolvers.java (84%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/injection/ModifyVarInjectionPointSubResolver.java (75%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/special/InjectorOrdinalResolver.java (93%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/special/ModifyVarAtReturnResolver.java (87%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/special/ModifyVarUpgradeResolver.java (81%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/special/ResolverSyntheticInstanceof.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/special/SliceBoundaryResolver.java (81%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/target/SplitMethodCancellationHelper.java (89%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/target/SplitTargetMethodSubResolver.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/target/TargetMethodResolver.java (77%) rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/patch}/resolver/target/TargetMethodSubResolvers.java (88%) create mode 100644 core/src/main/java/org/sinytra/adapter/transform/ClassTransformer.java create mode 100644 core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java rename {definition/src/next/java/org/sinytra/adapter/next/pipeline => core/src/main/java/org/sinytra/adapter/transform}/PipelineMethodTransformer.java (86%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/cls/DynamicAnonClassIndexPatch.java (87%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/cls/DynamicAnonymousShadowFieldTypePatch.java (86%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/InjectParameterTransform.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/InlineParameterTransformer.java (84%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/ModifyArgsOffsetUpgrader.java (87%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/MoveParametersTransformer.java (82%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/ParamTransformationUtil.java (87%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/ParameterTransformer.java (66%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/RemoveParameterTransformer.java (85%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/ReplaceParametersTransformer.java (84%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/SubstituteParameterTransformer.java (80%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/SwapParametersTransformer.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/param/TransformParameters.java (94%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/patch/ConfigurationMatcher.java (88%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/patch/MethodPatch.java (60%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/patch/MethodPatchBuilder.java (92%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/patch/MethodPatchBuilderImpl.java (90%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/patch/MethodPatchImpl.java (80%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/patch/MethodPatchTransformer.java (73%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/transform/preprocess/LocalCaptureUpgradeTransformer.java (81%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/BytecodeFixerJarGenerator.java (99%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/BytecodeFixerUpper.java (96%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/FieldAccessorTypeTransformer.java (91%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/FieldTypeUsageTransformer.java (91%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/ObjectTypeAdapter.java (96%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/SimpleTypeAdapter.java (94%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/SupplierTypeAdapter.java (97%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/TypeAdapter.java (89%) rename {definition/src/next/java/org/sinytra/adapter/next => core/src/main/java/org/sinytra/adapter}/types/TypeAdapterProvider.java (74%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/AdapterUtil.java (95%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/GeneratedVariables.java (99%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/MethodQualifier.java (98%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/OpcodeUtil.java (97%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/SingleValueHandle.java (93%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/provider/ClassLookup.java (93%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/provider/MixinClassLookup.java (94%) rename {definition/src/main/java/org/sinytra/adapter/patch => core/src/main/java/org/sinytra/adapter}/util/provider/ZipClassLookup.java (96%) delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/mixin/MixinType.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyReturnValueMixin.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigAttribute.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java delete mode 100644 definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f977903a..195c8dbd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: with: java: 21 pre_gradle_tasks: test - gradle_tasks: :publish :runtime:publish :definition:publish :userdev:publish + gradle_tasks: :publish :runtime:publish :core:publish :userdev:publish secrets: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} MAVEN_USER: ${{ secrets.MAVEN_USERNAME }} diff --git a/.gitignore b/.gitignore index 5b27b01a..cfcebeeb 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,5 @@ build eclipse run -definition/logs +core/logs test/logs \ No newline at end of file diff --git a/definition/build.gradle.kts b/core/build.gradle.kts similarity index 93% rename from definition/build.gradle.kts rename to core/build.gradle.kts index b9ca599b..60297dfb 100644 --- a/definition/build.gradle.kts +++ b/core/build.gradle.kts @@ -15,7 +15,7 @@ gradleutils.version { } version = gradleutils.version.toString() + "+$versionMc" -println("Definition version: $version") +println("Core version: $version") java { toolchain { @@ -24,11 +24,6 @@ java { withSourcesJar() } -sourceSets.main { - java.srcDirs("src/next/java") - resources.srcDirs("src/next/resources") -} - repositories { mavenCentral() maven { diff --git a/definition/settings.gradle.kts b/core/settings.gradle.kts similarity index 94% rename from definition/settings.gradle.kts rename to core/settings.gradle.kts index bd173db0..102c87c1 100644 --- a/definition/settings.gradle.kts +++ b/core/settings.gradle.kts @@ -17,4 +17,4 @@ gradle.beforeProject { } } -rootProject.name = "definition" +rootProject.name = "core" diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java b/core/src/main/java/org/sinytra/adapter/analysis/InheritanceHandler.java similarity index 94% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java rename to core/src/main/java/org/sinytra/adapter/analysis/InheritanceHandler.java index af078fb1..3d8c6bd7 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InheritanceHandler.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/InheritanceHandler.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.analysis; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.ClassLookup; import java.util.*; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InsnComparator.java b/core/src/main/java/org/sinytra/adapter/analysis/InsnComparator.java similarity index 99% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/InsnComparator.java rename to core/src/main/java/org/sinytra/adapter/analysis/InsnComparator.java index 09bc637d..9d0ad3ff 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InsnComparator.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/InsnComparator.java @@ -23,7 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.analysis; import org.objectweb.asm.tree.*; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InstructionMatcher.java b/core/src/main/java/org/sinytra/adapter/analysis/InstructionMatcher.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/InstructionMatcher.java rename to core/src/main/java/org/sinytra/adapter/analysis/InstructionMatcher.java index ad9a21be..6cf1d234 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/InstructionMatcher.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/InstructionMatcher.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.analysis; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodLabelComparator.java b/core/src/main/java/org/sinytra/adapter/analysis/MethodLabelComparator.java similarity index 97% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodLabelComparator.java rename to core/src/main/java/org/sinytra/adapter/analysis/MethodLabelComparator.java index 38f582b5..ff0f50be 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/MethodLabelComparator.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/MethodLabelComparator.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis; +package org.sinytra.adapter.analysis; import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.Nullable; @@ -6,8 +6,8 @@ import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.pipeline.Recipe; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.patch.Recipe; import java.util.*; import java.util.stream.Stream; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LVTSnapshot.java b/core/src/main/java/org/sinytra/adapter/analysis/locals/LVTSnapshot.java similarity index 95% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LVTSnapshot.java rename to core/src/main/java/org/sinytra/adapter/analysis/locals/LVTSnapshot.java index 5261c2fc..171af333 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LVTSnapshot.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/locals/LVTSnapshot.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.locals; +package org.sinytra.adapter.analysis.locals; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; import it.unimi.dsi.fastutil.ints.Int2IntMap; @@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.SingleValueHandle; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.SingleValueHandle; import java.util.*; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVarAnalyzer.java similarity index 92% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java rename to core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVarAnalyzer.java index de70b9d0..c3ca9952 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVarAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVarAnalyzer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.locals; +package org.sinytra.adapter.analysis.locals; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; @@ -7,14 +7,14 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; -import org.sinytra.adapter.next.env.ctx.LocalVariable; -import org.sinytra.adapter.next.transform.param.TransformParameters; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.OpcodeUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; +import org.sinytra.adapter.env.ctx.LocalVariable; +import org.sinytra.adapter.transform.param.TransformParameters; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.OpcodeUtil; import java.util.ArrayList; import java.util.Collections; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java rename to core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java index 9337a0dd..430ecc36 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/locals/LocalVariableLookup.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.locals; +package org.sinytra.adapter.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/analysis/method/MethodAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodAnalyzer.java similarity index 96% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java rename to core/src/main/java/org/sinytra/adapter/analysis/method/MethodAnalyzer.java index 9257bca7..27b87ef7 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodAnalyzer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.method; +package org.sinytra.adapter.analysis.method; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; @@ -7,10 +7,10 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.analysis.*; -import org.sinytra.adapter.next.env.util.TypeConstants; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.OpcodeUtil; +import org.sinytra.adapter.env.util.TypeConstants; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; +import org.sinytra.adapter.util.OpcodeUtil; import java.util.ArrayList; import java.util.Collection; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java similarity index 94% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java rename to core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java index 2830ad66..b2a1e118 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodCallAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.method; +package org.sinytra.adapter.analysis.method; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; @@ -9,10 +9,10 @@ import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; -import org.sinytra.adapter.patch.analysis.InsnComparator; -import org.sinytra.adapter.patch.analysis.selector.FrameUtil; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.analysis.InsnComparator; +import org.sinytra.adapter.analysis.selector.FrameUtil; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodInsnMatcher.java b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodInsnMatcher.java similarity index 96% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodInsnMatcher.java rename to core/src/main/java/org/sinytra/adapter/analysis/method/MethodInsnMatcher.java index c7b3aa3b..254af0b4 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/method/MethodInsnMatcher.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodInsnMatcher.java @@ -1,11 +1,11 @@ -package org.sinytra.adapter.patch.analysis.method; +package org.sinytra.adapter.analysis.method; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LineNumberNode; -import org.sinytra.adapter.patch.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.InstructionMatcher; import java.util.List; import java.util.Objects; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java b/core/src/main/java/org/sinytra/adapter/analysis/params/EnhancedParamsDiff.java similarity index 99% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java rename to core/src/main/java/org/sinytra/adapter/analysis/params/EnhancedParamsDiff.java index f5248bcd..253c3838 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/EnhancedParamsDiff.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/EnhancedParamsDiff.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.params; +package org.sinytra.adapter.analysis.params; import com.google.common.collect.MapDifference; import com.google.common.collect.Maps; @@ -9,14 +9,14 @@ 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.sinytra.adapter.util.GeneratedVariables; import org.slf4j.Logger; import java.util.*; public class EnhancedParamsDiff { private static final Logger LOGGER = LogUtils.getLogger(); - private static final boolean DEBUG = Boolean.getBoolean("adapter.definition.paramdiff.debug"); + private static final boolean DEBUG = Boolean.getBoolean("adapter.core.paramdiff.debug"); public static LayeredParamsDiffSnapshot createLayered(List clean, List dirty) { LayeredParamsDiffSnapshot.Builder builder = LayeredParamsDiffSnapshot.builder(); diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java b/core/src/main/java/org/sinytra/adapter/analysis/params/LayeredParamsDiffSnapshot.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java rename to core/src/main/java/org/sinytra/adapter/analysis/params/LayeredParamsDiffSnapshot.java index d20cec59..b8763f02 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/LayeredParamsDiffSnapshot.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/LayeredParamsDiffSnapshot.java @@ -1,11 +1,12 @@ -package org.sinytra.adapter.patch.analysis.params; +package org.sinytra.adapter.analysis.params; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CheckReturnValue; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.next.transform.param.*; +import org.sinytra.adapter.transform.param.*; +import org.sinytra.adapter.transform.param.*; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParametersDiff.java b/core/src/main/java/org/sinytra/adapter/analysis/params/ParametersDiff.java similarity index 97% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParametersDiff.java rename to core/src/main/java/org/sinytra/adapter/analysis/params/ParametersDiff.java index 3ce49354..b5b7a002 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParametersDiff.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/ParametersDiff.java @@ -1,10 +1,10 @@ -package org.sinytra.adapter.patch.analysis.params; +package org.sinytra.adapter.analysis.params; import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.GeneratedVariables; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.GeneratedVariables; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java b/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshot.java similarity index 87% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java rename to core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshot.java index 8d804f68..f7ed70c6 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshot.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshot.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.patch.analysis.params; +package org.sinytra.adapter.analysis.params; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.next.transform.param.TransformParameters; +import org.sinytra.adapter.transform.param.TransformParameters; import java.util.List; import java.util.Set; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshotBuilder.java b/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshotBuilder.java similarity index 96% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshotBuilder.java rename to core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshotBuilder.java index a9ab13f0..90e572e1 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/params/ParamsDiffSnapshotBuilder.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshotBuilder.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.params; +package org.sinytra.adapter.analysis.params; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java rename to core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java index 3466e7d5..6abccffa 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationHandle.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.selector; +package org.sinytra.adapter.analysis.selector; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AnnotationNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationValueHandle.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationValueHandle.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationValueHandle.java rename to core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationValueHandle.java index ce439b78..ef1b0710 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/AnnotationValueHandle.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationValueHandle.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.selector; +package org.sinytra.adapter.analysis.selector; import org.objectweb.asm.tree.AnnotationNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FieldMatcher.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/FieldMatcher.java similarity index 93% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FieldMatcher.java rename to core/src/main/java/org/sinytra/adapter/analysis/selector/FieldMatcher.java index badbe9bc..727f96d3 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FieldMatcher.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/selector/FieldMatcher.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.selector; +package org.sinytra.adapter.analysis.selector; import org.jetbrains.annotations.Nullable; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FrameUtil.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/FrameUtil.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FrameUtil.java rename to core/src/main/java/org/sinytra/adapter/analysis/selector/FrameUtil.java index 248d1985..8c4a75d2 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/analysis/selector/FrameUtil.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/selector/FrameUtil.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.analysis.selector; +package org.sinytra.adapter.analysis.selector; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java b/core/src/main/java/org/sinytra/adapter/env/MixinContext.java similarity index 87% rename from definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java rename to core/src/main/java/org/sinytra/adapter/env/MixinContext.java index 9e98b497..fa418662 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/MixinContext.java +++ b/core/src/main/java/org/sinytra/adapter/env/MixinContext.java @@ -1,17 +1,17 @@ -package org.sinytra.adapter.next.env; +package org.sinytra.adapter.env; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ctx.*; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.next.types.TypeAdapter; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.env.ctx.*; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.types.TypeAdapter; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.provider.ClassLookup; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/MockMixinRuntime.java b/core/src/main/java/org/sinytra/adapter/env/MockMixinRuntime.java similarity index 98% rename from definition/src/next/java/org/sinytra/adapter/next/env/MockMixinRuntime.java rename to core/src/main/java/org/sinytra/adapter/env/MockMixinRuntime.java index 1adebedb..b39b4439 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/MockMixinRuntime.java +++ b/core/src/main/java/org/sinytra/adapter/env/MockMixinRuntime.java @@ -1,8 +1,8 @@ -package org.sinytra.adapter.next.env; +package org.sinytra.adapter.env; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.ctx.PatchEnvironment; -import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.TargetPair; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.extensibility.IMixinConfig; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java similarity index 89% rename from definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java rename to core/src/main/java/org/sinytra/adapter/env/ann/AtData.java index 792eef49..f5b95ca9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/AtData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java @@ -1,16 +1,16 @@ -package org.sinytra.adapter.next.env.ann; +package org.sinytra.adapter.env.ann; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; -import org.sinytra.adapter.next.env.ctx.RefMapper; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.config.MutablePropertyContainer; -import org.sinytra.adapter.next.pipeline.config.PropertyContainer; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.config.PropertyKey; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ctx.RefMapper; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.config.MutablePropertyContainer; +import org.sinytra.adapter.patch.config.PropertyContainer; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.PropertyKey; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.util.MethodQualifier; import org.spongepowered.asm.mixin.injection.At; import java.util.Objects; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java similarity index 85% rename from definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java rename to core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java index 1244758c..791ea463 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ClassTarget.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java @@ -1,15 +1,15 @@ -package org.sinytra.adapter.next.env.ann; +package org.sinytra.adapter.env.ann; import com.mojang.datafixers.util.Either; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; import java.util.List; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.MIXIN_TARGETS; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.MIXIN_VALUE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.MIXIN_TARGETS; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.MIXIN_VALUE; public class ClassTarget { private final AnnotationHandle handle; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java b/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java rename to core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java index 205fa5ad..e47993b6 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/ConstantData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java @@ -1,8 +1,8 @@ -package org.sinytra.adapter.next.env.ann; +package org.sinytra.adapter.env.ann; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; import java.util.List; import java.util.Optional; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java b/core/src/main/java/org/sinytra/adapter/env/ann/SliceData.java similarity index 78% rename from definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java rename to core/src/main/java/org/sinytra/adapter/env/ann/SliceData.java index f53c2998..187b0c7c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ann/SliceData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/SliceData.java @@ -1,14 +1,14 @@ -package org.sinytra.adapter.next.env.ann; +package org.sinytra.adapter.env.ann; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.tree.AnnotationNode; -import org.sinytra.adapter.next.env.ctx.RefMapper; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.RefMapper; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.SLICE_FROM; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.SLICE_TO; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.SLICE_FROM; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.SLICE_TO; public class SliceData { @Nullable diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrail.java b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrail.java similarity index 93% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrail.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrail.java index 56e7bf11..81ef0dfb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrail.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrail.java @@ -1,11 +1,11 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import it.unimi.dsi.fastutil.Pair; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.config.Configuration; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrailImpl.java b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrailImpl.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrailImpl.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrailImpl.java index eb04a170..e9eeaa79 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/AuditTrailImpl.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrailImpl.java @@ -1,20 +1,20 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.Pair; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; import org.slf4j.Logger; import java.text.DecimalFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public class AuditTrailImpl implements AuditTrail { private static final DecimalFormat FORMAT = new DecimalFormat("##.00"); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/Auditor.java b/core/src/main/java/org/sinytra/adapter/env/ctx/Auditor.java similarity index 70% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/Auditor.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/Auditor.java index b10323d4..59f8438e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/Auditor.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/Auditor.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; public interface Auditor { void recordAudit(Object transform, String message, Object... args); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/LocalVariable.java b/core/src/main/java/org/sinytra/adapter/env/ctx/LocalVariable.java similarity index 67% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/LocalVariable.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/LocalVariable.java index e9e0e3b4..1e79c497 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/LocalVariable.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/LocalVariable.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.objectweb.asm.Type; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodFinder.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/MethodFinder.java index efd1d7e7..76c40529 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodFinder.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodFinder.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; @@ -7,9 +7,9 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.analysis.InheritanceHandler; +import org.sinytra.adapter.util.MethodQualifier; +import org.sinytra.adapter.util.provider.ClassLookup; import org.slf4j.Logger; import java.util.Collection; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java similarity index 92% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java index 25456799..9b12d406 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MethodHelper.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; @@ -6,17 +6,17 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.ParamDiffResolver; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.next.env.MockMixinRuntime; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.ParamDiffResolver; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; +import org.sinytra.adapter.env.MockMixinRuntime; +import org.sinytra.adapter.util.provider.ClassLookup; import org.slf4j.Logger; import org.spongepowered.asm.mixin.injection.InjectionPoint; import org.spongepowered.asm.mixin.injection.code.ISliceContext; @@ -30,8 +30,8 @@ import java.util.function.Supplier; import java.util.stream.Stream; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.*; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.*; public class MethodHelper { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGenerator.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinClassGenerator.java similarity index 90% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGenerator.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/MixinClassGenerator.java index 5fb4af87..57bb1cf7 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGenerator.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinClassGenerator.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGeneratorImpl.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinClassGeneratorImpl.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGeneratorImpl.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/MixinClassGeneratorImpl.java index 0a10b2f2..034db1c6 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/MixinClassGeneratorImpl.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinClassGeneratorImpl.java @@ -1,11 +1,11 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.next.env.util.MixinAnnotations; +import org.sinytra.adapter.env.util.MixinAnnotations; import org.spongepowered.asm.service.MixinService; import java.io.IOException; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContext.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContext.java similarity index 92% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContext.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/PatchContext.java index ed062ede..a1a2c12b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContext.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContext.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContextImpl.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContextImpl.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContextImpl.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/PatchContextImpl.java index bdd5baa7..1f24b270 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchContextImpl.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContextImpl.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironment.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironment.java similarity index 82% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironment.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironment.java index 241c87dd..416dbadb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironment.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironment.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.next.types.BytecodeFixerUpper; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.analysis.InheritanceHandler; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.util.provider.ClassLookup; public interface PatchEnvironment { static PatchEnvironment create(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility, AuditTrail auditTrail) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironmentImpl.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironmentImpl.java similarity index 81% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironmentImpl.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironmentImpl.java index e899dd23..54518422 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchEnvironmentImpl.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironmentImpl.java @@ -1,10 +1,10 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.analysis.InheritanceHandler; -import org.sinytra.adapter.next.types.BytecodeFixerUpper; -import org.sinytra.adapter.patch.util.provider.ClassLookup; -import org.sinytra.adapter.patch.util.provider.MixinClassLookup; +import org.sinytra.adapter.analysis.InheritanceHandler; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.MixinClassLookup; public record PatchEnvironmentImpl( RefmapHolder refmapHolder, diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchResult.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchResult.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchResult.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/PatchResult.java index 3f328d9f..a083c60c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/PatchResult.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchResult.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; public enum PatchResult { PASS, diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefMapper.java b/core/src/main/java/org/sinytra/adapter/env/ctx/RefMapper.java similarity index 62% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefMapper.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/RefMapper.java index d006a70b..0c6f443f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefMapper.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/RefMapper.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; public interface RefMapper { String remap(String refmapEntry); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefmapHolder.java b/core/src/main/java/org/sinytra/adapter/env/ctx/RefmapHolder.java similarity index 75% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefmapHolder.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/RefmapHolder.java index 6281202b..28befb0e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/RefmapHolder.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/RefmapHolder.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; public interface RefmapHolder { String remap(String cls, String reference); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/TargetPair.java b/core/src/main/java/org/sinytra/adapter/env/ctx/TargetPair.java similarity index 79% rename from definition/src/next/java/org/sinytra/adapter/next/env/ctx/TargetPair.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/TargetPair.java index 7f84ed17..6b1572c3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ctx/TargetPair.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/TargetPair.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.ctx; +package org.sinytra.adapter.env.ctx; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Annotation.java b/core/src/main/java/org/sinytra/adapter/env/param/Annotation.java similarity index 98% rename from definition/src/next/java/org/sinytra/adapter/next/env/param/Annotation.java rename to core/src/main/java/org/sinytra/adapter/env/param/Annotation.java index 6e6557de..f4f05200 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/Annotation.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Annotation.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.param; +package org.sinytra.adapter.env.param; import com.google.common.collect.ImmutableMap; import org.objectweb.asm.AnnotationVisitor; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Copiable.java b/core/src/main/java/org/sinytra/adapter/env/param/Copiable.java similarity index 52% rename from definition/src/next/java/org/sinytra/adapter/next/env/param/Copiable.java rename to core/src/main/java/org/sinytra/adapter/env/param/Copiable.java index 313e8ac8..a549ef4e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/Copiable.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Copiable.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.param; +package org.sinytra.adapter.env.param; public interface Copiable { T copy(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java b/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java similarity index 98% rename from definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java rename to core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java index 16b32383..52a91a6f 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/MethodParameters.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.next.env.param; +package org.sinytra.adapter.env.param; import com.google.common.collect.ImmutableMap; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.util.TypeConstants; +import org.sinytra.adapter.env.util.TypeConstants; import java.util.*; import java.util.function.Predicate; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/ParamDiffResolver.java b/core/src/main/java/org/sinytra/adapter/env/param/ParamDiffResolver.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/env/param/ParamDiffResolver.java rename to core/src/main/java/org/sinytra/adapter/env/param/ParamDiffResolver.java index 3ec36c96..1aad951e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/ParamDiffResolver.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/ParamDiffResolver.java @@ -1,10 +1,10 @@ -package org.sinytra.adapter.next.env.param; +package org.sinytra.adapter.env.param; import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot.*; +import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; +import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot.*; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java b/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java rename to core/src/main/java/org/sinytra/adapter/env/param/Parameter.java index 8bd60585..6933ac1b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameter.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java @@ -1,8 +1,8 @@ -package org.sinytra.adapter.next.env.param; +package org.sinytra.adapter.env.param; import com.google.common.collect.ImmutableList; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.util.MixinAnnotations; +import org.sinytra.adapter.env.util.MixinAnnotations; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java b/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java rename to core/src/main/java/org/sinytra/adapter/env/param/Parameters.java index 2860624e..4a7707fc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/param/Parameters.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.param; +package org.sinytra.adapter.env.param; import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.Nullable; @@ -8,8 +8,8 @@ import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.SourceValue; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.selector.FrameUtil; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.selector.FrameUtil; import java.util.*; import java.util.stream.Collectors; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotationConstants.java b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotationConstants.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotationConstants.java rename to core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotationConstants.java index e1c3f342..96f833d0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotationConstants.java +++ b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotationConstants.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.util; +package org.sinytra.adapter.env.util; public class MixinAnnotationConstants { public static final String MIXIN_VALUE = "value"; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotations.java b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotations.java similarity index 98% rename from definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotations.java rename to core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotations.java index ed59a6d7..2b25ddd2 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/util/MixinAnnotations.java +++ b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotations.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.util; +package org.sinytra.adapter.env.util; public class MixinAnnotations { // Standard mixins diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/util/OrderedRegistry.java b/core/src/main/java/org/sinytra/adapter/env/util/OrderedRegistry.java similarity index 98% rename from definition/src/next/java/org/sinytra/adapter/next/env/util/OrderedRegistry.java rename to core/src/main/java/org/sinytra/adapter/env/util/OrderedRegistry.java index 0f477515..4a433131 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/util/OrderedRegistry.java +++ b/core/src/main/java/org/sinytra/adapter/env/util/OrderedRegistry.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.util; +package org.sinytra.adapter.env.util; import org.jetbrains.annotations.Nullable; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/util/TypeConstants.java b/core/src/main/java/org/sinytra/adapter/env/util/TypeConstants.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/env/util/TypeConstants.java rename to core/src/main/java/org/sinytra/adapter/env/util/TypeConstants.java index eee85cce..1bd863a5 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/util/TypeConstants.java +++ b/core/src/main/java/org/sinytra/adapter/env/util/TypeConstants.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.env.util; +package org.sinytra.adapter.env.util; import org.objectweb.asm.Type; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/util/WeighedDisambiguation.java b/core/src/main/java/org/sinytra/adapter/env/util/WeighedDisambiguation.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/env/util/WeighedDisambiguation.java rename to core/src/main/java/org/sinytra/adapter/env/util/WeighedDisambiguation.java index ab5ea813..91693f3e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/util/WeighedDisambiguation.java +++ b/core/src/main/java/org/sinytra/adapter/env/util/WeighedDisambiguation.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.next.env.util; +package org.sinytra.adapter.env.util; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.util.AdapterUtil; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java new file mode 100644 index 00000000..6121ab98 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java @@ -0,0 +1,31 @@ +package org.sinytra.adapter.patch; + +import org.sinytra.adapter.transform.PipelineMethodTransformer; +import org.sinytra.adapter.types.FieldAccessorTypeTransformer; +import org.sinytra.adapter.transform.MethodTransformer; +import org.sinytra.adapter.transform.cls.DynamicAnonClassIndexPatch; +import org.sinytra.adapter.transform.cls.DynamicAnonymousShadowFieldTypePatch; +import org.sinytra.adapter.transform.patch.MethodPatch; +import org.sinytra.adapter.transform.patch.MethodPatchTransformer; +import org.sinytra.adapter.transform.preprocess.LocalCaptureUpgradeTransformer; +import org.sinytra.adapter.transform.ClassTransformer; +import org.sinytra.adapter.types.FieldTypeUsageTransformer; + +import java.util.List; + +public class DynamicPatches { + public static final List CLASS_PATCHES = List.of( + new DynamicAnonClassIndexPatch(), + new DynamicAnonymousShadowFieldTypePatch(), + new FieldTypeUsageTransformer() + ); + + public static List methodTransformers(List patches) { + return List.of( + new FieldAccessorTypeTransformer(), // Interface mixin only + new LocalCaptureUpgradeTransformer(), + new MethodPatchTransformer(patches), + new PipelineMethodTransformer() + ); + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java similarity index 84% rename from definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java rename to core/src/main/java/org/sinytra/adapter/patch/MixinParser.java index 4edffb9d..687bbac3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/flow/MixinParser.java +++ b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java @@ -1,19 +1,19 @@ -package org.sinytra.adapter.next.flow; +package org.sinytra.adapter.patch; 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.MethodNode; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ctx.MethodHelper; -import org.sinytra.adapter.next.env.ctx.RefMapper; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.config.*; -import org.sinytra.adapter.next.mixin.MixinType; -import org.sinytra.adapter.next.mixin.MixinTypes; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.next.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.env.ctx.MethodHelper; +import org.sinytra.adapter.env.ctx.RefMapper; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.config.*; +import org.sinytra.adapter.patch.mixin.MixinType; +import org.sinytra.adapter.patch.mixin.MixinTypes; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.PatchEnvironment; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java similarity index 79% rename from definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java rename to core/src/main/java/org/sinytra/adapter/patch/Patcher.java index 1ae19e53..48831c95 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/flow/Patcher.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java @@ -1,28 +1,27 @@ -package org.sinytra.adapter.next.flow; +package org.sinytra.adapter.patch; import com.mojang.logging.LogUtils; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ctx.PatchContext; -import org.sinytra.adapter.next.env.ctx.PatchContextImpl; -import org.sinytra.adapter.next.env.ctx.PatchEnvironment; -import org.sinytra.adapter.next.env.util.MixinAnnotationConstants; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.next.mixin.MixinType; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.PatchContextImpl; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.util.MixinAnnotationConstants; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.transform.ClassTransformer; +import org.sinytra.adapter.transform.MethodTransformer; +import org.sinytra.adapter.patch.mixin.MixinType; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.MethodQualifier; import org.slf4j.Logger; import java.util.List; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public class Patcher { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java b/core/src/main/java/org/sinytra/adapter/patch/Recipe.java similarity index 89% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java rename to core/src/main/java/org/sinytra/adapter/patch/Recipe.java index 645ad2ee..37d29c4d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/Recipe.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Recipe.java @@ -1,13 +1,13 @@ -package org.sinytra.adapter.next.pipeline; +package org.sinytra.adapter.patch; import com.google.common.base.Suppliers; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import java.util.Objects; import java.util.Optional; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/TxResult.java b/core/src/main/java/org/sinytra/adapter/patch/TxResult.java similarity index 62% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/TxResult.java rename to core/src/main/java/org/sinytra/adapter/patch/TxResult.java index dcd56a44..3429d7b0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/TxResult.java +++ b/core/src/main/java/org/sinytra/adapter/patch/TxResult.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline; +package org.sinytra.adapter.patch; public enum TxResult { SUCCESS, diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java rename to core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java index 7d269453..b2b6c473 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/BasePropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java @@ -1,10 +1,10 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.env.ctx.RefMapper; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.env.ctx.RefMapper; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; import java.util.HashMap; import java.util.Map; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java b/core/src/main/java/org/sinytra/adapter/patch/config/Configuration.java similarity index 71% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java rename to core/src/main/java/org/sinytra/adapter/patch/config/Configuration.java index d4b7c2fc..89daf98d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Configuration.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/Configuration.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.util.MethodQualifier; public interface Configuration extends PropertyContainer { String getMixinType(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationImpl.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java rename to core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationImpl.java index d1eb7ca9..660fd6d6 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigurationImpl.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationImpl.java @@ -1,13 +1,13 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.param.Copiable; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.param.Copiable; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.util.MethodQualifier; /** * Contains a single recipe state with mixin parameters and custom variables diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationTemplates.java similarity index 79% rename from definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java rename to core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationTemplates.java index e6880820..0704c52e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/env/ConfigurationTemplates.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationTemplates.java @@ -1,7 +1,4 @@ -package org.sinytra.adapter.next.env; - -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; +package org.sinytra.adapter.patch.config; public final class ConfigurationTemplates { public static final PropertyContainerTemplate MIXIN_BASE = PropertyContainerTemplate.builder() diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/Configurations.java b/core/src/main/java/org/sinytra/adapter/patch/config/Configurations.java new file mode 100644 index 00000000..4529e496 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/config/Configurations.java @@ -0,0 +1,6 @@ +package org.sinytra.adapter.patch.config; + +public class Configurations { + public static final Configuration DELETE = MutableConfiguration.create(ConfigurationTemplates.DELETE) + .setShouldDelete(true); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java b/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java similarity index 90% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java rename to core/src/main/java/org/sinytra/adapter/patch/config/Keys.java index e62813cd..192c6c99 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/Keys.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java @@ -1,13 +1,13 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ConstantData; -import org.sinytra.adapter.next.env.ann.SliceData; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ann.ConstantData; +import org.sinytra.adapter.env.ann.SliceData; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.util.MethodQualifier; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java b/core/src/main/java/org/sinytra/adapter/patch/config/MutableConfiguration.java similarity index 89% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java rename to core/src/main/java/org/sinytra/adapter/patch/config/MutableConfiguration.java index 43341b7f..36966db3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutableConfiguration.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/MutableConfiguration.java @@ -1,13 +1,13 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.util.MethodQualifier; public interface MutableConfiguration extends Configuration, MutablePropertyContainer { static MutableConfiguration create() { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/MutablePropertyContainer.java similarity index 85% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java rename to core/src/main/java/org/sinytra/adapter/patch/config/MutablePropertyContainer.java index f15d3fe4..023ebc07 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/MutablePropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/MutablePropertyContainer.java @@ -1,8 +1,8 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.env.ctx.RefMapper; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.RefMapper; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; public interface MutablePropertyContainer extends PropertyContainer { static MutablePropertyContainer create() { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainer.java similarity index 85% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainer.java rename to core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainer.java index 0f4d5157..140ab1ca 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import java.util.Map; import java.util.Optional; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainerTemplate.java similarity index 97% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java rename to core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainerTemplate.java index 355a2a8d..2fabd93d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyContainerTemplate.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainerTemplate.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java rename to core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java index d91abbf3..25f71f4e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/PropertyKey.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java @@ -1,8 +1,8 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import com.google.common.base.MoreObjects; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.env.ctx.RefMapper; +import org.sinytra.adapter.env.ctx.RefMapper; import java.util.Objects; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/SpecialKeys.java b/core/src/main/java/org/sinytra/adapter/patch/config/SpecialKeys.java similarity index 91% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/config/SpecialKeys.java rename to core/src/main/java/org/sinytra/adapter/patch/config/SpecialKeys.java index 7dfd45ce..223ee6fc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/SpecialKeys.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/SpecialKeys.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.config; +package org.sinytra.adapter.patch.config; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.MethodInsnNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/InjectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java similarity index 72% rename from definition/src/next/java/org/sinytra/adapter/next/mixin/InjectMixin.java rename to core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java index 64dfc70a..26466c61 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/InjectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java @@ -1,25 +1,25 @@ -package org.sinytra.adapter.next.mixin; +package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.ConfigurationTemplates; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.Parameter; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.*; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.ComparingInjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.InjectorOrdinalResolver; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameter; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.config.*; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.resolver.injection.ArbitraryInjectionPointSubResolver; +import org.sinytra.adapter.patch.resolver.injection.AtVariableAssignStoreSubResolver; +import org.sinytra.adapter.patch.resolver.injection.ComparingInjectionPointResolver; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.patch.resolver.special.InjectorOrdinalResolver; import java.util.List; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.*; public class InjectMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java new file mode 100644 index 00000000..bcd07f90 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java @@ -0,0 +1,21 @@ +package org.sinytra.adapter.patch.mixin; + +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; + +/** + * Handles configuration and behavior specific to a Mixin type + */ +public interface MixinType { + PropertyContainerTemplate getConfigurationTemplate(); + + TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors); + + TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinTypes.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinTypes.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/mixin/MixinTypes.java rename to core/src/main/java/org/sinytra/adapter/patch/mixin/MixinTypes.java index 732bbbc8..14d7f2fb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinTypes.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinTypes.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.next.mixin; +package org.sinytra.adapter.patch.mixin; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.env.util.MixinAnnotations; +import org.sinytra.adapter.env.util.MixinAnnotations; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyVariable; diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyArgMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java similarity index 70% rename from definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyArgMixin.java rename to core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java index dd02d533..5eb7ee03 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyArgMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java @@ -1,30 +1,30 @@ -package org.sinytra.adapter.next.mixin; +package org.sinytra.adapter.patch.mixin; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.ConfigurationTemplates; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.Parameter; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.types.TypeAdapter; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameter; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.resolver.injection.ArbitraryInjectionPointSubResolver; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.types.TypeAdapter; +import org.sinytra.adapter.util.MethodQualifier; import java.util.List; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; -import static org.sinytra.adapter.next.pipeline.config.Keys.INDEX; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.SINGLE_ANY; +import static org.sinytra.adapter.patch.config.Keys.INDEX; public class ModifyArgMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyExpressionValueMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java similarity index 60% rename from definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyExpressionValueMixin.java rename to core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java index 30b3b40c..471c1a86 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyExpressionValueMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java @@ -1,26 +1,26 @@ -package org.sinytra.adapter.next.mixin; +package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.ConfigurationTemplates; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.pipeline.resolver.injection.ArbitraryInjectionPointSubResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.resolver.injection.ArbitraryInjectionPointSubResolver; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.patch.resolver.special.ResolverSyntheticInstanceof; +import org.sinytra.adapter.util.MethodQualifier; import java.util.List; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.SINGLE_ANY; public class ModifyExpressionValueMixin implements MixinType { @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java new file mode 100644 index 00000000..dad9cd58 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java @@ -0,0 +1,32 @@ +package org.sinytra.adapter.patch.mixin; + +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.patch.resolver.special.InjectorOrdinalResolver; + +// TODO +public class ModifyReturnValueMixin implements MixinType { + @Override + public PropertyContainerTemplate getConfigurationTemplate() { + return null; + } + + @Override + public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { + resolvers + .addBefore(InjectionPointResolver.class, new InjectorOrdinalResolver()); + return null; + } + + @Override + public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { + return null; + } +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyVariableMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java similarity index 63% rename from definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyVariableMixin.java rename to core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java index 640f1453..46a98f51 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyVariableMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java @@ -1,30 +1,30 @@ -package org.sinytra.adapter.next.mixin; +package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.ConfigurationTemplates; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.Parameter; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.ModifyVarInjectionPointSubResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.InjectorOrdinalResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.ModifyVarAtReturnResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.ModifyVarUpgradeResolver; -import org.sinytra.adapter.next.types.TypeAdapter; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameter; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.patch.resolver.injection.ModifyVarInjectionPointSubResolver; +import org.sinytra.adapter.patch.resolver.special.InjectorOrdinalResolver; +import org.sinytra.adapter.patch.resolver.special.ModifyVarAtReturnResolver; +import org.sinytra.adapter.patch.resolver.special.ModifyVarUpgradeResolver; +import org.sinytra.adapter.types.TypeAdapter; import java.util.List; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.LOCALS; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.SINGLE_ANY; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.LOCALS; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.SINGLE_ANY; public class ModifyVariableMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/RedirectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java similarity index 64% rename from definition/src/next/java/org/sinytra/adapter/next/mixin/RedirectMixin.java rename to core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java index d62ff3c5..5d23c515 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/RedirectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java @@ -1,30 +1,30 @@ -package org.sinytra.adapter.next.mixin; +package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.ConfigurationTemplates; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.util.MixinAnnotationConstants; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.processor.redirect.ParameterUsageProcessor; -import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.ResolverSyntheticInstanceof; -import org.sinytra.adapter.next.pipeline.processor.redirect.DivertRedirectProcessor; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.util.MixinAnnotationConstants; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.processor.redirect.ParameterUsageProcessor; +import org.sinytra.adapter.patch.processor.ParametersProcessor; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.patch.resolver.special.ResolverSyntheticInstanceof; +import org.sinytra.adapter.patch.processor.redirect.DivertRedirectProcessor; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; public class RedirectMixin implements MixinType { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/WrapOperationMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java similarity index 64% rename from definition/src/next/java/org/sinytra/adapter/next/mixin/WrapOperationMixin.java rename to core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java index 8f941169..d2cb66dc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/WrapOperationMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java @@ -1,32 +1,32 @@ -package org.sinytra.adapter.next.mixin; +package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.ConfigurationTemplates; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.MethodHelper; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.ParametersProcessor; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.processor.wrapop.WrapOpParamsProcessor; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.pipeline.resolver.injection.AtVariableAssignStoreSubResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.ComparingInjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.env.util.TypeConstants; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MethodHelper; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.ParametersProcessor; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.processor.wrapop.WrapOpParamsProcessor; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.resolver.injection.AtVariableAssignStoreSubResolver; +import org.sinytra.adapter.patch.resolver.injection.ComparingInjectionPointResolver; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.env.util.TypeConstants; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; -import static org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup.*; +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.*; public class WrapOperationMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_BASE.extend() diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/DisableMixinProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java similarity index 64% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/DisableMixinProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java index 804b5af0..2560aede 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/DisableMixinProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; public class DisableMixinProcessor implements Processor { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java similarity index 68% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java index 810cce67..29d01a55 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/InjectionTargetProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java @@ -1,14 +1,14 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.ConstantData; -import org.sinytra.adapter.next.env.util.MixinAnnotationConstants; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.ConstantData; +import org.sinytra.adapter.env.util.MixinAnnotationConstants; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; public class InjectionTargetProcessor implements Processor { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinTypeProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java similarity index 73% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinTypeProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java index 390dd02f..5e29c3f7 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/MixinTypeProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java @@ -1,12 +1,12 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; public class MixinTypeProcessor implements Processor { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java similarity index 80% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java index a01a956f..2001dcb9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ParametersProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java @@ -1,17 +1,17 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.tree.VarInsnNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot; -import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; +import org.sinytra.adapter.env.ctx.PatchResult; import java.util.List; import java.util.Map; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java new file mode 100644 index 00000000..b26a57cb --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java @@ -0,0 +1,10 @@ +package org.sinytra.adapter.patch.processor; + +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; + +public interface Processor { + TxResult process(MixinContext context, Configuration dirty, Recipe recipe); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java b/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java similarity index 74% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java index 0c4236e5..6e2a1bc2 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processors.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; -import org.sinytra.adapter.next.env.util.OrderedRegistry; -import org.sinytra.adapter.next.pipeline.processor.extract.ExtractMixinProcessor; +import org.sinytra.adapter.env.util.OrderedRegistry; +import org.sinytra.adapter.patch.processor.extract.ExtractMixinProcessor; public class Processors extends OrderedRegistry { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java similarity index 55% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java index 9c735564..7a451230 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/PropertyProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java @@ -1,13 +1,13 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; -import static org.sinytra.adapter.next.pipeline.config.Keys.ORDINAL; -import static org.sinytra.adapter.next.pipeline.config.Keys.SLICE; +import static org.sinytra.adapter.patch.config.Keys.ORDINAL; +import static org.sinytra.adapter.patch.config.Keys.SLICE; public class PropertyProcessor implements Processor { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ReturnTypeProcessor.java similarity index 81% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/ReturnTypeProcessor.java index 998ce30e..c5e6d86a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/ReturnTypeProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ReturnTypeProcessor.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -6,13 +6,13 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.next.types.TypeAdapter; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.types.TypeAdapter; +import org.sinytra.adapter.util.AdapterUtil; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/StaticAccessProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java similarity index 85% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/StaticAccessProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java index 6a43c902..129dbdbb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/StaticAccessProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -6,12 +6,12 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.MethodHelper; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.SpecialKeys; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MethodHelper; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.SpecialKeys; public class StaticAccessProcessor implements Processor { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/TargetMethodProcessor.java similarity index 71% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/TargetMethodProcessor.java index 63aea43e..661f49bf 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/TargetMethodProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/TargetMethodProcessor.java @@ -1,17 +1,17 @@ -package org.sinytra.adapter.next.pipeline.processor; +package org.sinytra.adapter.patch.processor; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.next.env.ctx.LocalVariable; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.env.ctx.LocalVariable; +import org.sinytra.adapter.util.AdapterUtil; import java.util.List; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_METHOD; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_METHOD; public class TargetMethodProcessor implements Processor { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java index dcde16b9..9de1e8eb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/ExtractMixinProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.processor.extract; +package org.sinytra.adapter.patch.processor.extract; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -6,21 +6,21 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.SpecialKeys; -import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.next.transform.param.TransformParameters; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.OpcodeUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.transform.param.TransformParameters; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.OpcodeUtil; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java similarity index 84% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java index ea02cc14..cf97559d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/extract/MirrorableExtractMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.processor.extract; +package org.sinytra.adapter.patch.processor.extract; import com.google.common.collect.ImmutableList; import org.objectweb.asm.Opcodes; @@ -6,24 +6,24 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.PatchEnvironment; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.env.util.TypeConstants; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.patch.util.OpcodeUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.env.util.TypeConstants; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; +import org.sinytra.adapter.util.OpcodeUtil; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.stream.Stream; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_METHOD; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_METHOD; // TODO Cleanup public class MirrorableExtractMixin { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/DivertRedirectProcessor.java similarity index 78% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/redirect/DivertRedirectProcessor.java index 6c6f2a3e..5080dadb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/DivertRedirectProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/DivertRedirectProcessor.java @@ -1,19 +1,19 @@ -package org.sinytra.adapter.next.pipeline.processor.redirect; +package org.sinytra.adapter.patch.processor.redirect; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.SpecialKeys; -import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.util.MethodQualifier; import java.util.function.Consumer; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class DivertRedirectProcessor implements Processor { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java similarity index 75% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java index bf99f6a5..7770d18e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/redirect/ParameterUsageProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java @@ -1,13 +1,13 @@ -package org.sinytra.adapter.next.pipeline.processor.redirect; +package org.sinytra.adapter.patch.processor.redirect; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.util.MethodQualifier; public class ParameterUsageProcessor implements Processor { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpAnalyzer.java similarity index 95% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpAnalyzer.java index eb8d1315..ccad6f9d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpAnalyzer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.processor.wrapop; +package org.sinytra.adapter.patch.processor.wrapop; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; @@ -6,8 +6,8 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.SourceValue; -import org.sinytra.adapter.patch.analysis.selector.FrameUtil; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.analysis.selector.FrameUtil; +import org.sinytra.adapter.util.AdapterUtil; import java.util.ArrayList; import java.util.HashMap; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java similarity index 90% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java index 9c3cbdcf..486b3177 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpParamsProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java @@ -1,20 +1,20 @@ -package org.sinytra.adapter.next.pipeline.processor.wrapop; +package org.sinytra.adapter.patch.processor.wrapop; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.Parameter; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameter; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.Collection; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpSurgeon.java similarity index 91% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java rename to core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpSurgeon.java index ad6e358f..44a4dbb8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/wrapop/WrapOpSurgeon.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpSurgeon.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.processor.wrapop; +package org.sinytra.adapter.patch.processor.wrapop; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; @@ -7,15 +7,15 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.next.types.BytecodeFixerUpper; -import org.sinytra.adapter.next.types.TypeAdapter; -import org.sinytra.adapter.next.transform.param.ParamTransformationUtil; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.OpcodeUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.types.TypeAdapter; +import org.sinytra.adapter.transform.param.ParamTransformationUtil; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.OpcodeUtil; import java.util.ArrayList; import java.util.HashMap; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java index 8c7f2847..c1d78f94 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/CompoundResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.next.pipeline.resolver; +package org.sinytra.adapter.patch.resolver; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolver.java similarity index 83% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/Resolver.java index 2966dd40..dc595ec0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolver.java @@ -1,10 +1,10 @@ -package org.sinytra.adapter.next.pipeline.resolver; +package org.sinytra.adapter.patch.resolver; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; import java.util.Optional; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolvers.java similarity index 54% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/Resolvers.java index 326df5bd..05a95668 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/Resolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolvers.java @@ -1,9 +1,9 @@ -package org.sinytra.adapter.next.pipeline.resolver; +package org.sinytra.adapter.patch.resolver; -import org.sinytra.adapter.next.env.util.OrderedRegistry; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.SliceBoundaryResolver; -import org.sinytra.adapter.next.pipeline.resolver.target.TargetMethodResolver; +import org.sinytra.adapter.env.util.OrderedRegistry; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.patch.resolver.special.SliceBoundaryResolver; +import org.sinytra.adapter.patch.resolver.target.TargetMethodResolver; public class Resolvers extends OrderedRegistry { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java new file mode 100644 index 00000000..02fb341a --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java @@ -0,0 +1,11 @@ +package org.sinytra.adapter.patch.resolver; + +import org.jetbrains.annotations.Nullable; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; + +public interface SubResolver { + @Nullable + Configuration resolve(MixinContext context, Recipe recipe); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java similarity index 83% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java index a3b5680d..ea8bcd59 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ArbitraryInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java @@ -1,28 +1,28 @@ -package org.sinytra.adapter.next.pipeline.resolver.injection; +package org.sinytra.adapter.patch.resolver.injection; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.analysis.InsnComparator; -import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.analysis.InsnComparator; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.function.UnaryOperator; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class ArbitraryInjectionPointSubResolver implements SubResolver { @Nullable diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/AtVariableAssignStoreSubResolver.java similarity index 85% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/injection/AtVariableAssignStoreSubResolver.java index 24ca19e1..c45f42c0 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/AtVariableAssignStoreSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/AtVariableAssignStoreSubResolver.java @@ -1,21 +1,21 @@ -package org.sinytra.adapter.next.pipeline.resolver.injection; +package org.sinytra.adapter.patch.resolver.injection; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.OpcodeUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.OpcodeUtil; import java.util.ArrayList; import java.util.List; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; /** * Find our new injection point with relation to variable assignments diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ComparingInjectionPointResolver.java similarity index 89% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ComparingInjectionPointResolver.java index 58bb8934..de43f561 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ComparingInjectionPointResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ComparingInjectionPointResolver.java @@ -1,37 +1,37 @@ -package org.sinytra.adapter.next.pipeline.resolver.injection; +package org.sinytra.adapter.patch.resolver.injection; import com.google.common.collect.Multimap; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.ConstantData; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup; -import org.sinytra.adapter.next.env.param.Parameter; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.env.util.TypeConstants; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.SpecialKeys; -import org.sinytra.adapter.next.pipeline.processor.wrapop.WrapOpSurgeon; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.analysis.MethodLabelComparator; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ann.ConstantData; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.MethodParameters.ParamGroup; +import org.sinytra.adapter.env.param.Parameter; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.env.util.TypeConstants; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.processor.wrapop.WrapOpSurgeon; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.analysis.MethodLabelComparator; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.util.MethodQualifier; import java.util.Collection; import java.util.List; import java.util.Optional; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.PROPERTY_ORDINAL; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.PROPERTY_ORDINAL; public abstract class ComparingInjectionPointResolver implements SubResolver { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InheritedInjectionPointSubResolver.java similarity index 71% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InheritedInjectionPointSubResolver.java index eb5c9a3c..9aca076c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InheritedInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InheritedInjectionPointSubResolver.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.resolver.injection; +package org.sinytra.adapter.patch.resolver.injection; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; @@ -6,24 +6,24 @@ import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodInsnNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.param.MethodParameters; -import org.sinytra.adapter.next.env.param.MethodParameters.ParamGroup; -import org.sinytra.adapter.next.env.param.Parameter; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.next.env.ctx.PatchContext; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.types.BytecodeFixerUpper; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.MethodParameters.ParamGroup; +import org.sinytra.adapter.env.param.Parameter; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.util.MethodQualifier; import java.util.List; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; // TODO Test public class InheritedInjectionPointSubResolver implements SubResolver { @@ -38,9 +38,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { TargetPair targetPair = recipe.getDirtyTarget(); if (targetPair == null) return null; - - List insns = context.methods().findInjectionTargetInsns(targetPair); - if (!insns.isEmpty()) return null; + if (context.methods().hasInjectionTargetInsns(targetPair)) return null; String owner = atTarget.internalOwnerName(); for (AbstractInsnNode insn : targetPair.methodNode().instructions) { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java similarity index 73% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java index a3c49a00..214fc54e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java @@ -1,12 +1,12 @@ -package org.sinytra.adapter.next.pipeline.resolver.injection; +package org.sinytra.adapter.patch.resolver.injection; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AbstractInsnNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; -import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.resolver.CompoundResolver; +import org.sinytra.adapter.env.ctx.TargetPair; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java similarity index 84% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java index ec5bfd2e..063cbad8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/InjectionPointSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.resolver.injection; +package org.sinytra.adapter.patch.resolver.injection; import com.google.common.collect.Multimap; import org.objectweb.asm.Type; @@ -6,23 +6,23 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.util.WeighedDisambiguation; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.util.WeighedDisambiguation; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class InjectionPointSubResolvers { public static final SubResolver REPLACED_TYPE = (MixinContext context, Recipe recipe) -> { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ModifyVarInjectionPointSubResolver.java similarity index 75% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ModifyVarInjectionPointSubResolver.java index 5b32d8a9..f78e3a01 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/injection/ModifyVarInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ModifyVarInjectionPointSubResolver.java @@ -1,23 +1,23 @@ -package org.sinytra.adapter.next.pipeline.resolver.injection; +package org.sinytra.adapter.patch.resolver.injection; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.env.ctx.TargetPair; import java.util.List; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_STORE; -import static org.sinytra.adapter.next.pipeline.config.Keys.ORDINAL; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_STORE; +import static org.sinytra.adapter.patch.config.Keys.ORDINAL; public class ModifyVarInjectionPointSubResolver implements SubResolver { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java similarity index 93% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java index 58fae008..61ecbc0e 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/InjectorOrdinalResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.resolver.special; +package org.sinytra.adapter.patch.resolver.special; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; @@ -6,31 +6,31 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ctx.PatchContext; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.patch.analysis.InsnComparator; -import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.GeneratedVariables; -import org.sinytra.adapter.patch.util.SingleValueHandle; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.Resolver; +import org.sinytra.adapter.analysis.InsnComparator; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.GeneratedVariables; +import org.sinytra.adapter.util.SingleValueHandle; import java.util.*; import java.util.function.Function; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_RETURN; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_RETURN; public class InjectorOrdinalResolver implements Resolver { private static final Map OFFSET_HANDLERS = Map.of( diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java similarity index 87% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java index af923749..f2172764 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarAtReturnResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java @@ -1,28 +1,28 @@ -package org.sinytra.adapter.next.pipeline.resolver.special; +package org.sinytra.adapter.patch.resolver.special; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.VarInsnNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.MockMixinRuntime; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.resolver.Resolver; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.MockMixinRuntime; import org.spongepowered.asm.mixin.injection.modify.LocalVariableDiscriminator; import org.spongepowered.asm.mixin.injection.struct.InjectionInfo; import org.spongepowered.asm.mixin.injection.struct.Target; import java.util.List; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_RETURN; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_RETURN; /** * Original mixin: diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarUpgradeResolver.java similarity index 81% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarUpgradeResolver.java index f2514fa9..eaa43f94 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ModifyVarUpgradeResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarUpgradeResolver.java @@ -1,15 +1,15 @@ -package org.sinytra.adapter.next.pipeline.resolver.special; +package org.sinytra.adapter.patch.resolver.special; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.resolver.Resolver; import org.spongepowered.asm.mixin.injection.At; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN; /** * Upgrade a ModifyVar to a ModifyExpressionVal diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ResolverSyntheticInstanceof.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/special/ResolverSyntheticInstanceof.java index 62ba08d9..1990dfc3 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/ResolverSyntheticInstanceof.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ResolverSyntheticInstanceof.java @@ -1,25 +1,25 @@ -package org.sinytra.adapter.next.pipeline.resolver.special; +package org.sinytra.adapter.patch.resolver.special; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.Configurations; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.patch.analysis.InsnComparator; -import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.next.env.ctx.TargetPair; +import org.sinytra.adapter.patch.config.Configurations; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.resolver.Resolver; +import org.sinytra.adapter.analysis.InsnComparator; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; +import org.sinytra.adapter.env.ctx.TargetPair; import java.util.ArrayList; import java.util.List; import java.util.Map; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_SINYTRA_INSTANCEOF; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_SINYTRA_INSTANCEOF; /** *

diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/SliceBoundaryResolver.java similarity index 81% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/special/SliceBoundaryResolver.java index ed51817b..055fa824 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/special/SliceBoundaryResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/SliceBoundaryResolver.java @@ -1,20 +1,20 @@ -package org.sinytra.adapter.next.pipeline.resolver.special; +package org.sinytra.adapter.patch.resolver.special; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.SliceData; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.util.MethodQualifier; -import org.sinytra.adapter.next.env.MockMixinRuntime; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ann.SliceData; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.Resolver; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.util.MethodQualifier; +import org.sinytra.adapter.env.MockMixinRuntime; import org.spongepowered.asm.mixin.injection.code.ISliceContext; import org.spongepowered.asm.mixin.injection.code.MethodSlice; import org.spongepowered.asm.mixin.injection.struct.Target; @@ -24,8 +24,8 @@ import java.util.List; import java.util.Optional; -import static org.sinytra.adapter.next.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.next.pipeline.config.Keys.SLICE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.patch.config.Keys.SLICE; public class SliceBoundaryResolver implements Resolver { @Override diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java similarity index 89% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java index 4b7d4854..d7a5fbca 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitMethodCancellationHelper.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.resolver.target; +package org.sinytra.adapter.patch.resolver.target; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; @@ -7,15 +7,15 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.next.env.ctx.MixinClassGenerator; -import org.sinytra.adapter.next.env.util.TypeConstants; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.env.ctx.MixinClassGenerator; +import org.sinytra.adapter.env.util.TypeConstants; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java index 2a5e3ac8..c08d7237 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/SplitTargetMethodSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java @@ -1,21 +1,21 @@ -package org.sinytra.adapter.next.pipeline.resolver.target; +package org.sinytra.adapter.patch.resolver.target; import com.google.common.collect.Multimap; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.patch.analysis.InsnComparator; -import org.sinytra.adapter.patch.analysis.InstructionMatcher; -import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.analysis.InsnComparator; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java similarity index 77% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java index c083e419..2026c0fd 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java @@ -1,11 +1,11 @@ -package org.sinytra.adapter.next.pipeline.resolver.target; +package org.sinytra.adapter.patch.resolver.target; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.resolver.CompoundResolver; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.resolver.CompoundResolver; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.util.MethodQualifier; public class TargetMethodResolver extends CompoundResolver { public TargetMethodResolver() { diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java rename to core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java index 8b374651..fc65f2ca 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/target/TargetMethodSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.pipeline.resolver.target; +package org.sinytra.adapter.patch.resolver.target; import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.Nullable; @@ -7,16 +7,16 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.next.pipeline.resolver.SubResolver; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.Resolver; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.Comparator; import java.util.List; diff --git a/core/src/main/java/org/sinytra/adapter/transform/ClassTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/ClassTransformer.java new file mode 100644 index 00000000..18ebf08c --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/transform/ClassTransformer.java @@ -0,0 +1,10 @@ +package org.sinytra.adapter.transform; + +import org.objectweb.asm.tree.ClassNode; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.PatchResult; + +public interface ClassTransformer { + PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context); +} diff --git a/core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java new file mode 100644 index 00000000..7599b631 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java @@ -0,0 +1,9 @@ +package org.sinytra.adapter.transform; + +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.env.ctx.PatchResult; + +public interface MethodTransformer { + PatchResult apply(MixinContext context, Configuration config); +} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java similarity index 86% rename from definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java index cbefabe0..85a11a4a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/PipelineMethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java @@ -1,26 +1,27 @@ -package org.sinytra.adapter.next.pipeline; +package org.sinytra.adapter.transform; import com.mojang.logging.LogUtils; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.env.ann.SliceData; -import org.sinytra.adapter.next.env.ctx.AuditTrail; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolver; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.next.mixin.MixinType; -import org.sinytra.adapter.next.mixin.MixinTypes; -import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ann.SliceData; +import org.sinytra.adapter.env.ctx.AuditTrail; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolver; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.patch.mixin.MixinType; +import org.sinytra.adapter.patch.mixin.MixinTypes; +import org.sinytra.adapter.env.ctx.PatchResult; import org.slf4j.Logger; import org.spongepowered.asm.mixin.injection.InjectionPoint; import org.spongepowered.asm.mixin.injection.points.BeforeConstant; @@ -28,7 +29,7 @@ import java.util.List; import java.util.Objects; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public class PipelineMethodTransformer implements MethodTransformer { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java similarity index 87% rename from definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java rename to core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java index 6ab69f12..8457719c 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonClassIndexPatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java @@ -1,18 +1,18 @@ -package org.sinytra.adapter.next.transform.cls; +package org.sinytra.adapter.transform.cls; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.mixin.MixinTypes; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.next.env.ctx.PatchContext; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.patch.mixin.MixinTypes; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.transform.ClassTransformer; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonymousShadowFieldTypePatch.java similarity index 86% rename from definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java rename to core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonymousShadowFieldTypePatch.java index d2c7c81b..0aea7cac 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/cls/DynamicAnonymousShadowFieldTypePatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonymousShadowFieldTypePatch.java @@ -1,15 +1,15 @@ -package org.sinytra.adapter.next.transform.cls; +package org.sinytra.adapter.transform.cls; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ctx.PatchContext; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.transform.ClassTransformer; +import org.sinytra.adapter.util.AdapterUtil; import java.util.Collection; import java.util.HashMap; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/InjectParameterTransform.java b/core/src/main/java/org/sinytra/adapter/transform/param/InjectParameterTransform.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/InjectParameterTransform.java rename to core/src/main/java/org/sinytra/adapter/transform/param/InjectParameterTransform.java index a624b934..616d2407 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/InjectParameterTransform.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/InjectParameterTransform.java @@ -1,20 +1,20 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.TypeReference; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.analysis.locals.LVTSnapshot; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.PatchResult; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.sinytra.adapter.next.transform.param.ParamTransformationUtil.calculateLVTIndex; +import static org.sinytra.adapter.transform.param.ParamTransformationUtil.calculateLVTIndex; // TODO Cleanup param transformers public record InjectParameterTransform(int index, Type type) implements ParameterTransformer { diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/InlineParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/InlineParameterTransformer.java similarity index 84% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/InlineParameterTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/param/InlineParameterTransformer.java index e416f42c..13c91384 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/InlineParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/InlineParameterTransformer.java @@ -1,20 +1,20 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.locals.LVTSnapshot; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; import org.slf4j.Logger; import java.util.Comparator; import java.util.List; import java.util.function.Consumer; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public record InlineParameterTransformer(int target, Consumer adapter) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ModifyArgsOffsetUpgrader.java b/core/src/main/java/org/sinytra/adapter/transform/param/ModifyArgsOffsetUpgrader.java similarity index 87% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/ModifyArgsOffsetUpgrader.java rename to core/src/main/java/org/sinytra/adapter/transform/param/ModifyArgsOffsetUpgrader.java index 9534265f..cfb7d2d2 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ModifyArgsOffsetUpgrader.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ModifyArgsOffsetUpgrader.java @@ -1,12 +1,12 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/MoveParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/MoveParametersTransformer.java similarity index 82% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/MoveParametersTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/param/MoveParametersTransformer.java index c4ad6154..e396225d 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/MoveParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/MoveParametersTransformer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; @@ -6,16 +6,16 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.ParameterNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.locals.LVTSnapshot; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; import org.slf4j.Logger; import java.util.List; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public record MoveParametersTransformer(int from, int to) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParamTransformationUtil.java b/core/src/main/java/org/sinytra/adapter/transform/param/ParamTransformationUtil.java similarity index 87% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/ParamTransformationUtil.java rename to core/src/main/java/org/sinytra/adapter/transform/param/ParamTransformationUtil.java index fdb0514a..c899579a 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParamTransformationUtil.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ParamTransformationUtil.java @@ -1,15 +1,15 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/ParameterTransformer.java similarity index 66% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/ParameterTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/param/ParameterTransformer.java index 4fae60ce..e3769f23 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ParameterTransformer.java @@ -1,10 +1,10 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.PatchResult; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/RemoveParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/RemoveParameterTransformer.java similarity index 85% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/RemoveParameterTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/param/RemoveParameterTransformer.java index 37d2b305..6b96a881 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/RemoveParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/RemoveParameterTransformer.java @@ -1,13 +1,13 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.locals.LVTSnapshot; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ReplaceParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java similarity index 84% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/ReplaceParametersTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java index e66d8918..67983483 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/ReplaceParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java @@ -1,23 +1,23 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.param.Parameters; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.patch.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.next.types.BytecodeFixerUpper; -import org.sinytra.adapter.next.types.TypeAdapter; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.types.TypeAdapter; import org.slf4j.Logger; import java.util.List; -import static org.sinytra.adapter.next.transform.param.ParamTransformationUtil.findWrapOperationOriginalCall; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.transform.param.ParamTransformationUtil.findWrapOperationOriginalCall; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; // TODO Just add @Coerce if the types are inherited public record ReplaceParametersTransformer(int index, Type type, boolean upgradeUsage) implements ParameterTransformer { diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/SubstituteParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/SubstituteParameterTransformer.java similarity index 80% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/SubstituteParameterTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/param/SubstituteParameterTransformer.java index c64a927d..c8286cbe 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/SubstituteParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/SubstituteParameterTransformer.java @@ -1,18 +1,18 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.patch.analysis.locals.LVTSnapshot; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.locals.LVTSnapshot; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; import org.slf4j.Logger; import java.util.List; -import static org.sinytra.adapter.next.transform.param.ParamTransformationUtil.calculateLVTIndex; +import static org.sinytra.adapter.transform.param.ParamTransformationUtil.calculateLVTIndex; public record SubstituteParameterTransformer(int target, int substitute) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/SwapParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/SwapParametersTransformer.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/SwapParametersTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/param/SwapParametersTransformer.java index d319bc06..382530df 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/SwapParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/SwapParametersTransformer.java @@ -1,18 +1,18 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.SingleValueHandle; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.SingleValueHandle; import org.slf4j.Logger; import java.util.List; import java.util.function.Consumer; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public record SwapParametersTransformer(int from, int to) implements ParameterTransformer { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/param/TransformParameters.java b/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/transform/param/TransformParameters.java rename to core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java index bf37c856..b57e1fd7 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/param/TransformParameters.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.transform.param; +package org.sinytra.adapter.transform.param; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; @@ -7,10 +7,10 @@ import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.PatchResult; import java.util.ArrayList; import java.util.Arrays; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/ConfigurationMatcher.java b/core/src/main/java/org/sinytra/adapter/transform/patch/ConfigurationMatcher.java similarity index 88% rename from definition/src/next/java/org/sinytra/adapter/next/transform/patch/ConfigurationMatcher.java rename to core/src/main/java/org/sinytra/adapter/transform/patch/ConfigurationMatcher.java index 15214645..d7b31afa 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/ConfigurationMatcher.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/ConfigurationMatcher.java @@ -1,8 +1,8 @@ -package org.sinytra.adapter.next.transform.patch; +package org.sinytra.adapter.transform.patch; import com.google.common.collect.ImmutableMap; -import org.sinytra.adapter.next.pipeline.config.PropertyContainer; -import org.sinytra.adapter.next.pipeline.config.PropertyKey; +import org.sinytra.adapter.patch.config.PropertyContainer; +import org.sinytra.adapter.patch.config.PropertyKey; import java.util.HashMap; import java.util.Map; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatch.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatch.java similarity index 60% rename from definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatch.java rename to core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatch.java index b6f62825..53d137b8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatch.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.next.transform.patch; +package org.sinytra.adapter.transform.patch; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.transform.MethodTransformer; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilder.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java similarity index 92% rename from definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilder.java rename to core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java index c6e1cfb9..cd89baee 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilder.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.next.transform.patch; +package org.sinytra.adapter.transform.patch; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.transform.MethodTransformer; import java.util.function.Consumer; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java similarity index 90% rename from definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java rename to core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java index d7fa3681..e8361705 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchBuilderImpl.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java @@ -1,11 +1,11 @@ -package org.sinytra.adapter.next.transform.patch; +package org.sinytra.adapter.transform.patch; import org.objectweb.asm.commons.InstructionAdapter; -import org.sinytra.adapter.next.env.ann.AtData; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.SpecialKeys; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.transform.MethodTransformer; +import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; @@ -14,7 +14,7 @@ import java.util.stream.Stream; import static java.util.function.Predicate.isEqual; -import static org.sinytra.adapter.next.pipeline.config.Keys.*; +import static org.sinytra.adapter.patch.config.Keys.*; public class MethodPatchBuilderImpl implements MethodPatchBuilder { private final ConfigurationMatcher.Builder matcher = ConfigurationMatcher.builder(); @@ -109,7 +109,7 @@ public MethodPatchBuilder modifyInjectionPoint(String value, String target, bool @Override public MethodPatchBuilder modifyStatic(boolean isStatic) { - // TODO Attribute + this.config.setProperty(SpecialKeys.STATIC, isStatic); return this; } diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchImpl.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchImpl.java similarity index 80% rename from definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchImpl.java rename to core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchImpl.java index bfa5a392..ed6ce9fc 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchImpl.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchImpl.java @@ -1,7 +1,7 @@ -package org.sinytra.adapter.next.transform.patch; +package org.sinytra.adapter.transform.patch; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.transform.MethodTransformer; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.transform.MethodTransformer; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchTransformer.java similarity index 73% rename from definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchTransformer.java index 8366cdd0..265b8ae8 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/patch/MethodPatchTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchTransformer.java @@ -1,19 +1,20 @@ -package org.sinytra.adapter.next.transform.patch; +package org.sinytra.adapter.transform.patch; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.processor.Processor; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.next.env.ctx.PatchResult; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.resolver.Resolvers; +import org.sinytra.adapter.transform.MethodTransformer; +import org.sinytra.adapter.env.ctx.PatchResult; import java.util.ArrayList; import java.util.List; +// TODO Merge into patch flow? public class MethodPatchTransformer implements MethodTransformer { private final List patches; diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java similarity index 81% rename from definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java rename to core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java index a9f35a00..71d8a7f4 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/preprocess/LocalCaptureUpgradeTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java @@ -1,20 +1,20 @@ -package org.sinytra.adapter.next.transform.preprocess; +package org.sinytra.adapter.transform.preprocess; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.AuditTrail; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.Keys; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.patch.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.AuditTrail; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.transform.MethodTransformer; +import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; import java.util.ArrayList; import java.util.List; diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerJarGenerator.java b/core/src/main/java/org/sinytra/adapter/types/BytecodeFixerJarGenerator.java similarity index 99% rename from definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerJarGenerator.java rename to core/src/main/java/org/sinytra/adapter/types/BytecodeFixerJarGenerator.java index 692dca2e..5fb85fb6 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerJarGenerator.java +++ b/core/src/main/java/org/sinytra/adapter/types/BytecodeFixerJarGenerator.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerUpper.java b/core/src/main/java/org/sinytra/adapter/types/BytecodeFixerUpper.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerUpper.java rename to core/src/main/java/org/sinytra/adapter/types/BytecodeFixerUpper.java index 851671a8..8874ef54 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/BytecodeFixerUpper.java +++ b/core/src/main/java/org/sinytra/adapter/types/BytecodeFixerUpper.java @@ -1,10 +1,10 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; 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 org.sinytra.adapter.util.provider.ClassLookup; import java.util.List; import java.util.Map; diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/FieldAccessorTypeTransformer.java b/core/src/main/java/org/sinytra/adapter/types/FieldAccessorTypeTransformer.java similarity index 91% rename from definition/src/next/java/org/sinytra/adapter/next/types/FieldAccessorTypeTransformer.java rename to core/src/main/java/org/sinytra/adapter/types/FieldAccessorTypeTransformer.java index a1f43324..a3d2339b 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/FieldAccessorTypeTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/types/FieldAccessorTypeTransformer.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import com.mojang.datafixers.util.Pair; import org.objectweb.asm.AnnotationVisitor; @@ -6,13 +6,13 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.patch.analysis.selector.FieldMatcher; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.transform.MethodTransformer; +import org.sinytra.adapter.analysis.selector.FieldMatcher; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; // TODO Clean up maybe public class FieldAccessorTypeTransformer implements MethodTransformer { diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/FieldTypeUsageTransformer.java b/core/src/main/java/org/sinytra/adapter/types/FieldTypeUsageTransformer.java similarity index 91% rename from definition/src/next/java/org/sinytra/adapter/next/types/FieldTypeUsageTransformer.java rename to core/src/main/java/org/sinytra/adapter/types/FieldTypeUsageTransformer.java index 95e01376..e7185c77 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/FieldTypeUsageTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/types/FieldTypeUsageTransformer.java @@ -1,23 +1,23 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.patch.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.next.env.ctx.PatchContext; -import org.sinytra.adapter.next.env.ctx.PatchResult; -import org.sinytra.adapter.patch.util.AdapterUtil; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.transform.ClassTransformer; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.AdapterUtil; import org.slf4j.Logger; import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.sinytra.adapter.patch.util.AdapterUtil.MIXINPATCH; +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public class FieldTypeUsageTransformer implements ClassTransformer { private static final Logger LOGGER = LogUtils.getLogger(); diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/ObjectTypeAdapter.java b/core/src/main/java/org/sinytra/adapter/types/ObjectTypeAdapter.java similarity index 96% rename from definition/src/next/java/org/sinytra/adapter/next/types/ObjectTypeAdapter.java rename to core/src/main/java/org/sinytra/adapter/types/ObjectTypeAdapter.java index 24c10cb9..895f61c2 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/ObjectTypeAdapter.java +++ b/core/src/main/java/org/sinytra/adapter/types/ObjectTypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/SimpleTypeAdapter.java b/core/src/main/java/org/sinytra/adapter/types/SimpleTypeAdapter.java similarity index 94% rename from definition/src/next/java/org/sinytra/adapter/next/types/SimpleTypeAdapter.java rename to core/src/main/java/org/sinytra/adapter/types/SimpleTypeAdapter.java index 18ca0c31..b31c6137 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/SimpleTypeAdapter.java +++ b/core/src/main/java/org/sinytra/adapter/types/SimpleTypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/SupplierTypeAdapter.java b/core/src/main/java/org/sinytra/adapter/types/SupplierTypeAdapter.java similarity index 97% rename from definition/src/next/java/org/sinytra/adapter/next/types/SupplierTypeAdapter.java rename to core/src/main/java/org/sinytra/adapter/types/SupplierTypeAdapter.java index 7c3ef16a..7a8c2ed9 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/SupplierTypeAdapter.java +++ b/core/src/main/java/org/sinytra/adapter/types/SupplierTypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapter.java b/core/src/main/java/org/sinytra/adapter/types/TypeAdapter.java similarity index 89% rename from definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapter.java rename to core/src/main/java/org/sinytra/adapter/types/TypeAdapter.java index c339c0e8..f4357b15 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapter.java +++ b/core/src/main/java/org/sinytra/adapter/types/TypeAdapter.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapterProvider.java b/core/src/main/java/org/sinytra/adapter/types/TypeAdapterProvider.java similarity index 74% rename from definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapterProvider.java rename to core/src/main/java/org/sinytra/adapter/types/TypeAdapterProvider.java index bb5cbcf5..2d8b4ceb 100644 --- a/definition/src/next/java/org/sinytra/adapter/next/types/TypeAdapterProvider.java +++ b/core/src/main/java/org/sinytra/adapter/types/TypeAdapterProvider.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.next.types; +package org.sinytra.adapter.types; import org.objectweb.asm.Type; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/AdapterUtil.java b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java similarity index 95% rename from definition/src/main/java/org/sinytra/adapter/patch/util/AdapterUtil.java rename to core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java index c992659d..1eb236a1 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/AdapterUtil.java +++ b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util; +package org.sinytra.adapter.util; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.ints.Int2IntFunction; @@ -11,16 +11,16 @@ import org.objectweb.asm.tree.analysis.SourceValue; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.env.ctx.MethodHelper; -import org.sinytra.adapter.next.env.ctx.PatchEnvironment; -import org.sinytra.adapter.next.env.ctx.TargetPair; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.next.env.util.TypeConstants; -import org.sinytra.adapter.next.pipeline.Recipe; -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.env.MixinContext; +import org.sinytra.adapter.env.ctx.MethodHelper; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.env.util.TypeConstants; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; import org.slf4j.Logger; import org.slf4j.Marker; import org.slf4j.MarkerFactory; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/GeneratedVariables.java b/core/src/main/java/org/sinytra/adapter/util/GeneratedVariables.java similarity index 99% rename from definition/src/main/java/org/sinytra/adapter/patch/util/GeneratedVariables.java rename to core/src/main/java/org/sinytra/adapter/util/GeneratedVariables.java index 3ab2fb01..7d82ebdd 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/GeneratedVariables.java +++ b/core/src/main/java/org/sinytra/adapter/util/GeneratedVariables.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util; +package org.sinytra.adapter.util; import com.google.common.base.Strings; import com.mojang.datafixers.util.Pair; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodQualifier.java b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java similarity index 98% rename from definition/src/main/java/org/sinytra/adapter/patch/util/MethodQualifier.java rename to core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java index 63b3c1e4..a4d62858 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/MethodQualifier.java +++ b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util; +package org.sinytra.adapter.util; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/OpcodeUtil.java b/core/src/main/java/org/sinytra/adapter/util/OpcodeUtil.java similarity index 97% rename from definition/src/main/java/org/sinytra/adapter/patch/util/OpcodeUtil.java rename to core/src/main/java/org/sinytra/adapter/util/OpcodeUtil.java index 57d81941..1e54cec0 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/OpcodeUtil.java +++ b/core/src/main/java/org/sinytra/adapter/util/OpcodeUtil.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util; +package org.sinytra.adapter.util; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/SingleValueHandle.java b/core/src/main/java/org/sinytra/adapter/util/SingleValueHandle.java similarity index 93% rename from definition/src/main/java/org/sinytra/adapter/patch/util/SingleValueHandle.java rename to core/src/main/java/org/sinytra/adapter/util/SingleValueHandle.java index fd43e1a5..de1aad00 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/SingleValueHandle.java +++ b/core/src/main/java/org/sinytra/adapter/util/SingleValueHandle.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util; +package org.sinytra.adapter.util; import java.util.function.Consumer; import java.util.function.Supplier; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/provider/ClassLookup.java b/core/src/main/java/org/sinytra/adapter/util/provider/ClassLookup.java similarity index 93% rename from definition/src/main/java/org/sinytra/adapter/patch/util/provider/ClassLookup.java rename to core/src/main/java/org/sinytra/adapter/util/provider/ClassLookup.java index 4ee5978e..4eba323e 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/provider/ClassLookup.java +++ b/core/src/main/java/org/sinytra/adapter/util/provider/ClassLookup.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util.provider; +package org.sinytra.adapter.util.provider; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/provider/MixinClassLookup.java b/core/src/main/java/org/sinytra/adapter/util/provider/MixinClassLookup.java similarity index 94% rename from definition/src/main/java/org/sinytra/adapter/patch/util/provider/MixinClassLookup.java rename to core/src/main/java/org/sinytra/adapter/util/provider/MixinClassLookup.java index 6f686f94..805cb9cb 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/provider/MixinClassLookup.java +++ b/core/src/main/java/org/sinytra/adapter/util/provider/MixinClassLookup.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util.provider; +package org.sinytra.adapter.util.provider; import com.mojang.logging.LogUtils; import org.objectweb.asm.tree.ClassNode; diff --git a/definition/src/main/java/org/sinytra/adapter/patch/util/provider/ZipClassLookup.java b/core/src/main/java/org/sinytra/adapter/util/provider/ZipClassLookup.java similarity index 96% rename from definition/src/main/java/org/sinytra/adapter/patch/util/provider/ZipClassLookup.java rename to core/src/main/java/org/sinytra/adapter/util/provider/ZipClassLookup.java index a169c74b..1e9f82b3 100644 --- a/definition/src/main/java/org/sinytra/adapter/patch/util/provider/ZipClassLookup.java +++ b/core/src/main/java/org/sinytra/adapter/util/provider/ZipClassLookup.java @@ -1,4 +1,4 @@ -package org.sinytra.adapter.patch.util.provider; +package org.sinytra.adapter.util.provider; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; diff --git a/definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java b/definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java deleted file mode 100644 index 28c67f8f..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/env/Configurations.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.sinytra.adapter.next.env; - -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; - -public class Configurations { - public static final Configuration DELETE = MutableConfiguration.create(ConfigurationTemplates.DELETE) - .setShouldDelete(true); -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java b/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java deleted file mode 100644 index b19d6b11..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/flow/DynamicPatches.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.sinytra.adapter.next.flow; - -import org.sinytra.adapter.next.pipeline.PipelineMethodTransformer; -import org.sinytra.adapter.next.types.FieldAccessorTypeTransformer; -import org.sinytra.adapter.next.transform.MethodTransformer; -import org.sinytra.adapter.next.transform.cls.DynamicAnonClassIndexPatch; -import org.sinytra.adapter.next.transform.cls.DynamicAnonymousShadowFieldTypePatch; -import org.sinytra.adapter.next.transform.patch.MethodPatch; -import org.sinytra.adapter.next.transform.patch.MethodPatchTransformer; -import org.sinytra.adapter.next.transform.preprocess.LocalCaptureUpgradeTransformer; -import org.sinytra.adapter.next.transform.ClassTransformer; -import org.sinytra.adapter.next.types.FieldTypeUsageTransformer; - -import java.util.List; - -public class DynamicPatches { - public static final List CLASS_PATCHES = List.of( - new DynamicAnonClassIndexPatch(), - new DynamicAnonymousShadowFieldTypePatch(), - new FieldTypeUsageTransformer() - ); - - public static List methodTransformers(List patches) { - return List.of( - new FieldAccessorTypeTransformer(), // Interface mixin only - new LocalCaptureUpgradeTransformer(), - new MethodPatchTransformer(patches), - new PipelineMethodTransformer() - ); - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinType.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinType.java deleted file mode 100644 index 9f3ddc98..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/MixinType.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.sinytra.adapter.next.mixin; - -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; - -/** - * Handles configuration and behavior specific to a Mixin type - */ -public interface MixinType { - PropertyContainerTemplate getConfigurationTemplate(); - - TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors); - - TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyReturnValueMixin.java b/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyReturnValueMixin.java deleted file mode 100644 index 46ab3873..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/mixin/ModifyReturnValueMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.sinytra.adapter.next.mixin; - -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.pipeline.config.MutableConfiguration; -import org.sinytra.adapter.next.pipeline.config.PropertyContainerTemplate; -import org.sinytra.adapter.next.pipeline.processor.Processors; -import org.sinytra.adapter.next.pipeline.resolver.Resolvers; -import org.sinytra.adapter.next.pipeline.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.next.pipeline.resolver.special.InjectorOrdinalResolver; - -// TODO -public class ModifyReturnValueMixin implements MixinType { - @Override - public PropertyContainerTemplate getConfigurationTemplate() { - return null; - } - - @Override - public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { - resolvers - .addBefore(InjectionPointResolver.class, new InjectorOrdinalResolver()); - return null; - } - - @Override - public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - return null; - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigAttribute.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigAttribute.java deleted file mode 100644 index a57a46e5..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/config/ConfigAttribute.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.sinytra.adapter.next.pipeline.config; - -import org.jetbrains.annotations.Nullable; - -import java.util.function.Supplier; - -public class ConfigAttribute { - private final String key; - private final boolean required; - - @Nullable - private T value; - @Nullable - private final Supplier defaultValueSupplier; - - public ConfigAttribute(String key, boolean required, @Nullable Supplier defaultValueSupplier) { - this.key = key; - this.required = required; - this.defaultValueSupplier = defaultValueSupplier; - } - - public String getKey() { - return this.key; - } - - public boolean validate() { - return !this.required || this.value != null; - } - - @Nullable - public T get() { - return this.value; - } - - public void set(@Nullable T value) { - this.value = value; - } - - public void setDefault() { - if (this.defaultValueSupplier != null) { - set(this.defaultValueSupplier.get()); - } else { - throw new IllegalStateException("No default value supplier set for %s".formatted(this.key)); - } - } -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java deleted file mode 100644 index f7a51af0..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/processor/Processor.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sinytra.adapter.next.pipeline.processor; - -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.TxResult; -import org.sinytra.adapter.next.pipeline.config.Configuration; - -public interface Processor { - TxResult process(MixinContext context, Configuration dirty, Recipe recipe); -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java b/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java deleted file mode 100644 index d65cfb8c..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/pipeline/resolver/SubResolver.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.sinytra.adapter.next.pipeline.resolver; - -import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.Recipe; -import org.sinytra.adapter.next.pipeline.config.Configuration; - -public interface SubResolver { - @Nullable - Configuration resolve(MixinContext context, Recipe recipe); -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java deleted file mode 100644 index 9c51fed3..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/ClassTransformer.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sinytra.adapter.next.transform; - -import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.next.env.ann.ClassTarget; -import org.sinytra.adapter.next.env.ctx.PatchContext; -import org.sinytra.adapter.next.env.ctx.PatchResult; - -public interface ClassTransformer { - PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context); -} diff --git a/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java b/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java deleted file mode 100644 index 25fcaac1..00000000 --- a/definition/src/next/java/org/sinytra/adapter/next/transform/MethodTransformer.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.sinytra.adapter.next.transform; - -import org.sinytra.adapter.next.env.MixinContext; -import org.sinytra.adapter.next.pipeline.config.Configuration; -import org.sinytra.adapter.next.env.ctx.PatchResult; - -public interface MethodTransformer { - PatchResult apply(MixinContext context, Configuration config); -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 5c2b22f0..abd99e01 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,6 +24,6 @@ pluginManagement { rootProject.name = "Adapter" +includeBuild("core") includeBuild("userdev") -includeBuild("definition") include("runtime", "test") \ No newline at end of file diff --git a/test/build.gradle.kts b/test/build.gradle.kts index 8607d2b1..d7c1fff2 100644 --- a/test/build.gradle.kts +++ b/test/build.gradle.kts @@ -24,8 +24,8 @@ configurations { } dependencies { - testImplementation(group = "org.sinytra.adapter", name = "definition") - "neoForgeTestLibraries"(group = "org.sinytra.adapter", name = "definition") { + testImplementation(group = "org.sinytra.adapter", name = "core") + "neoForgeTestLibraries"(group = "org.sinytra.adapter", name = "core") { isTransitive = false } @@ -41,7 +41,7 @@ dependencies { tasks { test { useJUnitPlatform() - systemProperty("adapter.definition.paramdiff.debug", true) + systemProperty("adapter.core.paramdiff.debug", true) systemProperty("adapter.clean.path", neoForge.additionalMinecraftArtifacts.getting("vanillaDeobfuscated").get().absolutePath) systemProperty("forge.logging.console.level", "debug") outputs.upToDateWhen { false } diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java index f5b8d54c..e64b9e5a 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/EnhancedParamsDiffTest.java @@ -3,8 +3,8 @@ import com.mojang.datafixers.util.Pair; import org.junit.jupiter.api.Test; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; import java.util.*; diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/ParamDiffResolverTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/ParamDiffResolverTest.java index 6555d1bc..f97b058b 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/ParamDiffResolverTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/ParamDiffResolverTest.java @@ -2,11 +2,11 @@ import org.junit.jupiter.api.Test; import org.objectweb.asm.Type; -import org.sinytra.adapter.next.env.param.ParamDiffResolver; -import org.sinytra.adapter.next.env.param.ParamDiffResolver.ParamEvalResult; -import org.sinytra.adapter.next.env.param.ParamDiffResolver.ParamState; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; +import org.sinytra.adapter.env.param.ParamDiffResolver; +import org.sinytra.adapter.env.param.ParamDiffResolver.ParamEvalResult; +import org.sinytra.adapter.env.param.ParamDiffResolver.ParamState; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; import java.io.InputStream; import java.io.OutputStream; diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java b/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java index 7ee8bd95..156e2e67 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/ParameterComparisonTest.java @@ -4,9 +4,9 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.patch.analysis.params.LayeredParamsDiffSnapshot; -import org.sinytra.adapter.patch.analysis.params.ParametersDiff; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; +import org.sinytra.adapter.analysis.params.ParametersDiff; import org.sinytra.adapter.patch.test.mixin.MinecraftMixinPatchTest; import java.io.IOException; diff --git a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java index f227e1d2..a604bb40 100644 --- a/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java +++ b/test/src/test/java/org/sinytra/adapter/patch/test/mixin/BytecodeFixerUpperTestFrontend.java @@ -6,14 +6,14 @@ import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.TypeInsnNode; -import org.sinytra.adapter.next.types.BytecodeFixerUpper; -import org.sinytra.adapter.next.types.SimpleTypeAdapter; -import org.sinytra.adapter.next.types.TypeAdapter; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.types.SimpleTypeAdapter; +import org.sinytra.adapter.types.TypeAdapter; +import org.sinytra.adapter.util.provider.ClassLookup; import java.util.List; -import static org.sinytra.adapter.patch.util.AdapterUtil.insnList; +import static org.sinytra.adapter.util.AdapterUtil.insnList; public class BytecodeFixerUpperTestFrontend { private static final List FIELD_TYPE_ADAPTERS = List.of( 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 f4dc3c7a..45e91fc5 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 @@ -5,12 +5,12 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.next.flow.DynamicPatches; -import org.sinytra.adapter.next.flow.Patcher; -import org.sinytra.adapter.next.env.ctx.PatchEnvironment; -import org.sinytra.adapter.next.env.ctx.RefmapHolder; -import org.sinytra.adapter.next.types.FieldTypeUsageTransformer; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.patch.DynamicPatches; +import org.sinytra.adapter.patch.Patcher; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.RefmapHolder; +import org.sinytra.adapter.types.FieldTypeUsageTransformer; +import org.sinytra.adapter.util.provider.ClassLookup; import org.slf4j.Logger; import org.spongepowered.asm.mixin.FabricUtil; 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 e18fa59d..61daf389 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 @@ -6,14 +6,14 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.next.env.util.MixinAnnotations; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.next.env.ctx.MixinClassGenerator; -import org.sinytra.adapter.next.env.ctx.PatchEnvironment; -import org.sinytra.adapter.patch.util.AdapterUtil; -import org.sinytra.adapter.patch.util.provider.ClassLookup; -import org.sinytra.adapter.patch.util.provider.ZipClassLookup; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.env.ctx.MixinClassGenerator; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.ZipClassLookup; import org.slf4j.Logger; import java.io.IOException; From c6758babe96330e50ac7bf1c0e5707721c1a1848 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Tue, 27 Jan 2026 12:54:33 +0100 Subject: [PATCH 09/27] Transformer pipeline phases --- .../sinytra/adapter/patch/DynamicPatches.java | 20 ++-- .../org/sinytra/adapter/patch/Patcher.java | 95 +++++++++++++------ .../org/sinytra/adapter/patch/TxPhase.java | 16 ++++ .../transform/PipelineMethodTransformer.java | 34 +++---- .../transform/patch/MethodPatchProcessor.java | 20 ++++ .../transform/patch/MethodPatchResolver.java | 48 ++++++++++ .../patch/MethodPatchTransformer.java | 68 ------------- gradle.properties | 2 +- .../test/mixin/DynamicMixinPatchTest.java | 15 ++- userdev/build.gradle.kts | 1 + 10 files changed, 186 insertions(+), 133 deletions(-) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/TxPhase.java create mode 100644 core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java create mode 100644 core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java delete mode 100644 core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchTransformer.java diff --git a/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java index 6121ab98..f32fdb61 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java +++ b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java @@ -1,14 +1,15 @@ package org.sinytra.adapter.patch; -import org.sinytra.adapter.transform.PipelineMethodTransformer; -import org.sinytra.adapter.types.FieldAccessorTypeTransformer; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import org.sinytra.adapter.transform.ClassTransformer; import org.sinytra.adapter.transform.MethodTransformer; +import org.sinytra.adapter.transform.PipelineMethodTransformer; import org.sinytra.adapter.transform.cls.DynamicAnonClassIndexPatch; import org.sinytra.adapter.transform.cls.DynamicAnonymousShadowFieldTypePatch; import org.sinytra.adapter.transform.patch.MethodPatch; -import org.sinytra.adapter.transform.patch.MethodPatchTransformer; import org.sinytra.adapter.transform.preprocess.LocalCaptureUpgradeTransformer; -import org.sinytra.adapter.transform.ClassTransformer; +import org.sinytra.adapter.types.FieldAccessorTypeTransformer; import org.sinytra.adapter.types.FieldTypeUsageTransformer; import java.util.List; @@ -20,12 +21,11 @@ public class DynamicPatches { new FieldTypeUsageTransformer() ); - public static List methodTransformers(List patches) { - return List.of( - new FieldAccessorTypeTransformer(), // Interface mixin only - new LocalCaptureUpgradeTransformer(), - new MethodPatchTransformer(patches), - new PipelineMethodTransformer() + public static Multimap methodTransformers(List patches) { + return ImmutableMultimap.of( + TxPhase.EARLY, new LocalCaptureUpgradeTransformer(), + TxPhase.LOADED, new FieldAccessorTypeTransformer(), // TODO EARLY? + TxPhase.VALIDATED, new PipelineMethodTransformer(patches) ); } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java index 48831c95..edee1c92 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java @@ -1,51 +1,48 @@ package org.sinytra.adapter.patch; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import com.mojang.logging.LogUtils; import org.objectweb.asm.tree.ClassNode; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.env.MixinContext; import org.sinytra.adapter.env.ann.ClassTarget; import org.sinytra.adapter.env.ctx.PatchContext; import org.sinytra.adapter.env.ctx.PatchContextImpl; import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.util.MixinAnnotationConstants; import org.sinytra.adapter.patch.config.Keys; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.mixin.MixinType; import org.sinytra.adapter.transform.ClassTransformer; import org.sinytra.adapter.transform.MethodTransformer; -import org.sinytra.adapter.patch.mixin.MixinType; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.util.MethodQualifier; import org.slf4j.Logger; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; public class Patcher { private static final Logger LOGGER = LogUtils.getLogger(); - - /* - Patcher phases: - - EARLY - Right after parsing, before preProcess is called - - AFTER_PRE - After preProcess is called - - VALIDATED - After clean config is validated - */ // TODO Support all known mixin types from PatchInstance (incl. interface mixins) private final PatchEnvironment environment; private final List classPatches; - private final List methodTransformers; + private final Multimap methodTransformers; - public Patcher(PatchEnvironment environment, List classPatches, List methodTransformers) { + private Patcher(PatchEnvironment environment, List classPatches, Multimap methodTransformers) { this.environment = environment; this.classPatches = classPatches; this.methodTransformers = methodTransformers; } - public PatchResult apply(ClassNode classNode) { - // 1. Parse mixin data + public PatchResult process(ClassNode classNode) { + // Parse mixin data MixinParser.MixinClassHandle mixinClass = MixinParser.parseMixins(classNode, this.environment); if (mixinClass == null) return PatchResult.PASS; @@ -53,12 +50,12 @@ public PatchResult apply(ClassNode classNode) { PatchResult result = PatchResult.PASS; PatchContextImpl context = new PatchContextImpl(classNode, classTarget.getTypes(), this.environment); - // 2. Class-level transformations + // Class-level transformations for (ClassTransformer patch : this.classPatches) { result = result.or(patch.apply(classNode, classTarget, context)); } - // 3. Mixin-level transformations + // Mixin-level transformations for (MixinParser.MixinMethodHandle mixin : mixinClass.mixins()) { PatchResult subResult = processMixin(classNode, classTarget, context, mixin); result = result.or(subResult); @@ -73,6 +70,7 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P MethodQualifier target = mixin.properties().getProperty(Keys.TARGET_METHOD).orElse(null); if (target == null) return PatchResult.PASS; + // Prepare context AnnotationHandle atHandle = mixin.methodAnnotation().getNested(MixinAnnotationConstants.PROPERTY_AT).orElse(null); MixinType mixinType = mixin.mixinType(); MixinContext mixinContext = new MixinContext(patchContext, classTarget, classNode, mixin.methodNode(), mixin.methodAnnotation(), atHandle); @@ -83,14 +81,25 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P MutableConfiguration configuration = MutableConfiguration.create(template); configuration.mergeFrom(mixin.properties()); - // << RUN EARLY PHASE TODO + PatchResult result = PatchResult.PASS; + // << RUN EARLY PHASE + for (MethodTransformer transformer : getTransformers(TxPhase.EARLY)) { + PatchResult txResult = transformer.apply(mixinContext, configuration); + result = result.or(txResult); + } - // 1. Complete and validate clean config + // Complete clean config TxResult preResult = mixinType.preProcess(mixinContext, configuration, mixinContext.getResolvers(), mixinContext.getProcessors()); if (preResult == TxResult.FAIL) { LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed preProcess", mixinId); return PatchResult.PASS; } + + // << RUN LOADED PHASE + for (MethodTransformer transformer : getTransformers(TxPhase.LOADED)) { + PatchResult txResult = transformer.apply(mixinContext, configuration); + result = result.or(txResult); + } // Validate clean config if (!configuration.validate()) { @@ -98,23 +107,51 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P return PatchResult.PASS; } - PatchResult result = PatchResult.PASS; // TODO Audit trail - if (!this.methodTransformers.isEmpty()) { - this.environment.auditTrail().prepareMethod(mixinContext); - } + this.environment.auditTrail().prepareMethod(mixinContext); - for (MethodTransformer transformer : this.methodTransformers) { + for (MethodTransformer transformer : getTransformers(TxPhase.VALIDATED)) { PatchResult txResult = transformer.apply(mixinContext, configuration); result = result.or(txResult); - - /* - if (txResult == PatchResult.APPLY && this.environment.auditTrail().getMatch(legacy) == PatchAuditTrail.Match.FULL) { - break; - } - */ } return result; } + + private Collection getTransformers(TxPhase phase) { + return this.methodTransformers.get(phase); + } + + public static Builder builder(PatchEnvironment environment) { + return new Builder(environment); + } + + public static class Builder { + private final PatchEnvironment environment; + private final List classTransformers = new ArrayList<>(); + private final Multimap methodTransformers = HashMultimap.create(); + + public Builder(PatchEnvironment environment) { + this.environment = environment; + } + + public Builder classTransformer(ClassTransformer transformer) { + this.classTransformers.add(transformer); + return this; + } + + public Builder methodTransformer(TxPhase phase, MethodTransformer transformer) { + this.methodTransformers.put(phase, transformer); + return this; + } + + public Builder methodTransformers(Multimap transformers) { + this.methodTransformers.putAll(transformers); + return this; + } + + public Patcher build() { + return new Patcher(this.environment, this.classTransformers, this.methodTransformers); + } + } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/TxPhase.java b/core/src/main/java/org/sinytra/adapter/patch/TxPhase.java new file mode 100644 index 00000000..cfb70222 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/TxPhase.java @@ -0,0 +1,16 @@ +package org.sinytra.adapter.patch; + +public enum TxPhase { + /** + * Right after parsing, before preProcess is called + */ + EARLY, + /** + * After preProcess is called + */ + LOADED, + /** + * After clean config is validated + */ + VALIDATED +} diff --git a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java index 85a11a4a..696383d0 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java @@ -4,24 +4,25 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.env.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.ann.SliceData; import org.sinytra.adapter.env.ctx.AuditTrail; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.Keys; import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.mixin.MixinType; +import org.sinytra.adapter.patch.mixin.MixinTypes; import org.sinytra.adapter.patch.processor.Processor; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolver; import org.sinytra.adapter.patch.resolver.Resolvers; -import org.sinytra.adapter.patch.mixin.MixinType; -import org.sinytra.adapter.patch.mixin.MixinTypes; -import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.transform.patch.MethodPatch; +import org.sinytra.adapter.transform.patch.MethodPatchResolver; import org.slf4j.Logger; import org.spongepowered.asm.mixin.injection.InjectionPoint; import org.spongepowered.asm.mixin.injection.points.BeforeConstant; @@ -34,26 +35,22 @@ public class PipelineMethodTransformer implements MethodTransformer { private static final Logger LOGGER = LogUtils.getLogger(); + private final List methodPatches; + + public PipelineMethodTransformer(List methodPatches) { + this.methodPatches = methodPatches; + } + @Override public PatchResult apply(MixinContext context, Configuration config) { TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), config.getTargetMethod()); - if (cleanTarget == null) - return PatchResult.PASS; + if (cleanTarget == null) return PatchResult.PASS; TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), config.getTargetMethod()); if (!failsDirtyInjectionCheck(context, dirtyTarget) && hasValidSlice(context, config, dirtyTarget)) return PatchResult.PASS; - AuditTrail.Match previousMatch = context.environment().auditTrail().getMatch(context); - if (previousMatch != null && previousMatch != AuditTrail.Match.NONE) - return PatchResult.PASS; - - String annotationInternalName = Type.getType(context.methodAnnotation().getDesc()).getInternalName(); - MixinType mixinType = MixinTypes.getMixinType(annotationInternalName); - if (mixinType == null) return PatchResult.PASS; - - ClassNode cls = context.classNode(); - LOGGER.debug(MIXINPATCH, "Considering method {}.{}", cls.name, cls.name); + LOGGER.debug(MIXINPATCH, "Considering method {}", context.getMixinId()); AuditTrail auditTrail = context.environment().auditTrail(); auditTrail.recordResult(context, config, AuditTrail.Match.NONE); @@ -72,6 +69,9 @@ private PatchResult execute(MixinContext context, Configuration config) { Resolvers resolvers = context.getResolvers(); Processors processors = context.getProcessors(); + // 0. Add highest priority manual patch resolver + resolvers.addFirst(new MethodPatchResolver(this.methodPatches)); + // 1. Create clean config from validated config MutableConfiguration cleanConfig = config.copy(); @@ -156,7 +156,7 @@ public boolean hasValidSlice(MixinContext context, Configuration config, @Nullab return false; SliceData slice = config.getProperty(Keys.SLICE).orElse(null); - if (slice == null) return false; + if (slice == null) return true; AtData from = slice.from(); if (from != null && !validateAtNode(context, from, target)) diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java new file mode 100644 index 00000000..389bbcf0 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java @@ -0,0 +1,20 @@ +package org.sinytra.adapter.transform.patch; + +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.transform.MethodTransformer; + +import java.util.List; + +public record MethodPatchProcessor(List transforms) implements Processor { + @Override + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { + for (MethodTransformer transformer : this.transforms) { + transformer.apply(context, recipe.clean()); + } + return TxResult.SUCCESS; + } +} diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java new file mode 100644 index 00000000..1a5a18bb --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java @@ -0,0 +1,48 @@ +package org.sinytra.adapter.transform.patch; + +import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.Resolver; +import org.sinytra.adapter.transform.MethodTransformer; + +import java.util.ArrayList; +import java.util.List; + +public class MethodPatchResolver implements Resolver { + private final List patches; + + public MethodPatchResolver(List patches) { + this.patches = patches; + } + + @Override + public ResolutionResult resolve(MixinContext context, Recipe recipe) { + List postChanges = new ArrayList<>(); + + Configuration config = recipe.clean(); + MutableConfiguration dirtyConfig = config.copyClean(); + boolean matched = false; + for (MethodPatch patch : this.patches) { + if (patch.matcher().match(config)) { + matched = true; + + Configuration patchConfig = patch.configuration(); + dirtyConfig.mergeFrom(patchConfig); + postChanges.addAll(patch.transforms()); + } + } + + if (matched) { + if (!postChanges.isEmpty()) { + // TODO Might get cancelled by earlier processor + recipe.processors().add(new MethodPatchProcessor(postChanges)); + } + + return ResolutionResult.replace(dirtyConfig); + } + + return ResolutionResult.pass(); + } +} diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchTransformer.java deleted file mode 100644 index 265b8ae8..00000000 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchTransformer.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.sinytra.adapter.transform.patch; - -import org.sinytra.adapter.env.MixinContext; -import org.sinytra.adapter.patch.Recipe; -import org.sinytra.adapter.patch.TxResult; -import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.MutableConfiguration; -import org.sinytra.adapter.patch.processor.Processor; -import org.sinytra.adapter.patch.processor.Processors; -import org.sinytra.adapter.patch.resolver.Resolvers; -import org.sinytra.adapter.transform.MethodTransformer; -import org.sinytra.adapter.env.ctx.PatchResult; - -import java.util.ArrayList; -import java.util.List; - -// TODO Merge into patch flow? -public class MethodPatchTransformer implements MethodTransformer { - private final List patches; - - public MethodPatchTransformer(List patches) { - this.patches = patches; - } - - @Override - public PatchResult apply(MixinContext context, Configuration config) { - Processors processors = new Processors(); - - List postChanges = new ArrayList<>(); - MutableConfiguration dirtyConfig = config.copyClean(); - boolean matched = false; - for (MethodPatch patch : this.patches) { - if (patch.matcher().match(config)) { - matched = true; - - Configuration patchConfig = patch.configuration(); - dirtyConfig.mergeFrom(patchConfig); - postChanges.addAll(patch.transforms()); - } - } - - // Apply changes - if (matched) { - Resolvers resolvers = new Resolvers(false); - Recipe recipe = new Recipe(config, dirtyConfig, resolvers, processors, context); - - processors.freeze(); - for (Processor processor : processors.getAll()) { - TxResult res = processor.process(context, dirtyConfig, recipe); - if (res == TxResult.FINALIZE) { - break; - } - if (res == TxResult.FAIL) { - return PatchResult.PASS; - } - } - - // Apply custom changes - for (MethodTransformer transformer : postChanges) { - transformer.apply(context, config); - } - - return PatchResult.APPLY; - } - - return PatchResult.PASS; - } -} diff --git a/gradle.properties b/gradle.properties index c4670d12..790689a0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,6 +8,6 @@ org.gradle.parallel=true versionMc=1.21.1 versionNeoForge=21.1.122 -versionModDevGradle=2.0.78 +versionModDevGradle=2.0.140 runtimeVersion=1.0.0 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 45e91fc5..77c61041 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 @@ -5,10 +5,10 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.DynamicPatches; -import org.sinytra.adapter.patch.Patcher; import org.sinytra.adapter.env.ctx.PatchEnvironment; import org.sinytra.adapter.env.ctx.RefmapHolder; +import org.sinytra.adapter.patch.DynamicPatches; +import org.sinytra.adapter.patch.Patcher; import org.sinytra.adapter.types.FieldTypeUsageTransformer; import org.sinytra.adapter.util.provider.ClassLookup; import org.slf4j.Logger; @@ -42,11 +42,10 @@ public void copyEntries(String from, String to) { new BytecodeFixerUpperTestFrontend(cleanLookup, dirtyLookup).unwrap(), FabricUtil.COMPATIBILITY_LATEST ); - patcher = new Patcher( - patchEnvironment, - List.of(new FieldTypeUsageTransformer()), - DynamicPatches.methodTransformers(List.of()) - ); + patcher = Patcher.builder(patchEnvironment) + .classTransformer(new FieldTypeUsageTransformer()) + .methodTransformers(DynamicPatches.methodTransformers(List.of())) + .build(); } @AfterAll @@ -430,7 +429,7 @@ void testSyntheticInstanceofMEV() throws Exception { protected LoadResult load(String className, List allowedMethods) throws Exception { ClassNode patched = loadClass(className); patched.methods.removeIf(m -> !allowedMethods.contains(m.name)); - patcher.apply(patched); + patcher.process(patched); return new LoadResult(patchEnvironment, patched, loadClass(className)); } } diff --git a/userdev/build.gradle.kts b/userdev/build.gradle.kts index ffeb1d89..d2cf0cbd 100644 --- a/userdev/build.gradle.kts +++ b/userdev/build.gradle.kts @@ -27,6 +27,7 @@ gradlePlugin { repositories { mavenCentral() + gradlePluginPortal() maven("https://maven.neoforged.net/releases") } From 5a7c0e5dce47701294bef0c118d356aa543617a8 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Tue, 27 Jan 2026 19:10:11 +0100 Subject: [PATCH 10/27] Stable frame analysis --- core/build.gradle.kts | 2 +- .../method/AdvancedSourceInterpreter.java | 118 ++++++++++++++++++ .../analysis/method/MethodCallAnalyzer.java | 22 ++-- .../adapter/analysis/selector/FrameUtil.java | 13 +- .../sinytra/adapter/patch/DynamicPatches.java | 2 +- .../org/sinytra/adapter/patch/Patcher.java | 5 + .../patch/processor/PropertyProcessor.java | 2 - .../processor/wrapop/WrapOpAnalyzer.java | 2 +- .../wrapop/WrapOpParamsProcessor.java | 7 +- .../transform/PipelineMethodTransformer.java | 6 +- .../transform/patch/ConfigurationMatcher.java | 2 +- .../transform/patch/MethodPatchBuilder.java | 6 + .../patch/MethodPatchBuilderImpl.java | 11 +- .../types/FieldTypeUsageTransformer.java | 1 + .../test/mixin/DynamicMixinPatchTest.java | 6 +- 15 files changed, 180 insertions(+), 25 deletions(-) create mode 100644 core/src/main/java/org/sinytra/adapter/analysis/method/AdvancedSourceInterpreter.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 60297dfb..45e61fe2 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -45,7 +45,7 @@ dependencies { compileOnly(group = "org.jetbrains", name = "annotations", version = "24.0.1") implementation(group = "io.github.llamalad7", name = "mixinextras-common", version = "0.3.1") - api(platform("org.ow2.asm:asm-bom:9.5")) + api(platform("org.ow2.asm:asm-bom:9.8")) api(group = "org.ow2.asm", name = "asm") api(group = "org.ow2.asm", name = "asm-commons") api(group = "org.ow2.asm", name = "asm-tree") diff --git a/core/src/main/java/org/sinytra/adapter/analysis/method/AdvancedSourceInterpreter.java b/core/src/main/java/org/sinytra/adapter/analysis/method/AdvancedSourceInterpreter.java new file mode 100644 index 00000000..39ec07c4 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/AdvancedSourceInterpreter.java @@ -0,0 +1,118 @@ +package org.sinytra.adapter.analysis.method; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.analysis.SourceInterpreter; +import org.objectweb.asm.tree.analysis.SourceValue; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class AdvancedSourceInterpreter extends SourceInterpreter { + private final boolean stable; + + public AdvancedSourceInterpreter(boolean stable) { + super(Opcodes.ASM9); + this.stable = stable; + } + + private static boolean isStackOp(int opcode) { + return opcode == Opcodes.DUP + || opcode == Opcodes.DUP_X1 + || opcode == Opcodes.DUP_X2 + || opcode == Opcodes.DUP2 + || opcode == Opcodes.DUP2_X1 + || opcode == Opcodes.DUP2_X2 + || opcode == Opcodes.SWAP; + } + + private SourceValue copyWithoutStackOps(SourceValue v) { + if (!this.stable || v.insns == null || v.insns.isEmpty()) { + return v; + } + + Set filtered = new HashSet<>(); + for (AbstractInsnNode insn : v.insns) { + if (!isStackOp(insn.getOpcode())) { + filtered.add(insn); + } + } + + // If everything was filtered out, keep the original + if (filtered.isEmpty()) { + return v; + } + + return new SourceValue(v.size, filtered); + } + + // Stack operations: never introduce new producers + @Override + public SourceValue copyOperation(AbstractInsnNode insn, SourceValue value) { + if (!this.stable || value.insns.isEmpty()) { + return super.copyOperation(insn, value); + } + return copyWithoutStackOps(value); + } + + @Override + public SourceValue unaryOperation(AbstractInsnNode insn, SourceValue value) { + return super.unaryOperation(insn, copyWithoutStackOps(value)); + } + + @Override + public SourceValue binaryOperation(AbstractInsnNode insn, SourceValue v1, SourceValue v2) { + return super.binaryOperation( + insn, + copyWithoutStackOps(v1), + copyWithoutStackOps(v2) + ); + } + + @Override + public SourceValue ternaryOperation(AbstractInsnNode insn, SourceValue v1, SourceValue v2, SourceValue v3) { + return super.ternaryOperation( + insn, + copyWithoutStackOps(v1), + copyWithoutStackOps(v2), + copyWithoutStackOps(v3) + ); + } + + @Override + public SourceValue naryOperation(AbstractInsnNode insn, List values) { + List cleaned = new ArrayList<>(values.size()); + for (SourceValue v : values) { + cleaned.add(copyWithoutStackOps(v)); + } + return super.naryOperation(insn, cleaned); + } + + // Always prefer original producers + @Override + public SourceValue merge(SourceValue v1, SourceValue v2) { + if (!this.stable) { + return super.merge(v1, v2); + } + + if (v1 == v2) { + return v1; + } + + SourceValue c1 = copyWithoutStackOps(v1); + SourceValue c2 = copyWithoutStackOps(v2); + + // If one side lost all stack ops and the other didn't, prefer the cleaner one + if (c1.insns != v1.insns && c2.insns == v2.insns) { + return c1; + } + if (c2.insns != v2.insns && c1.insns == v1.insns) { + return c2; + } + + return super.merge(c1, c2); + } +} + diff --git a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java index b2a1e118..e6b8b0d4 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java @@ -1,13 +1,11 @@ package org.sinytra.adapter.analysis.method; import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.Frame; -import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; import org.sinytra.adapter.analysis.InsnComparator; import org.sinytra.adapter.analysis.selector.FrameUtil; @@ -31,11 +29,12 @@ public static List getMethodCallInsns(MethodNode methodNode, M .orElse(null); } + // Uses true producer source values public static List> getAllMethodCallSrcInsnsInclusive(MethodNode methodNode, MethodQualifier qualifier) { List> list = new ArrayList<>(); for (AbstractInsnNode insn : methodNode.instructions) { if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { - List insns = getMethodCallSrcInsns(methodNode, minsn); + List insns = getMethodCallSrcInsns(methodNode, minsn, true); insns.add(minsn); if (insns != null) { list.add(insns); @@ -47,7 +46,12 @@ public static List> getAllMethodCallSrcInsnsInclusive(Met @Nullable public static List getMethodCallSrcInsns(MethodNode methodNode, MethodInsnNode minsn) { - List sources = Objects.requireNonNull(getCallSourceValues(methodNode, minsn)); + return getMethodCallSrcInsns(methodNode, minsn, false); + } + + @Nullable + public static List getMethodCallSrcInsns(MethodNode methodNode, MethodInsnNode minsn, boolean stable) { + List sources = Objects.requireNonNull(getCallSourceValues(methodNode, minsn, stable)); List insns = new ArrayList<>(); for (SourceValue src : sources) { @@ -98,17 +102,17 @@ private static void expandArgInitInsnsRecursive(List out, Insn } @Nullable - public static List getCallSourceValues(MethodNode methodNode, MethodInsnNode minsn) { - SourceValueInterpreter i = MethodAnalyzer.analyzeInterpretMethod(methodNode, new SourceValueInterpreter(minsn)); + public static List getCallSourceValues(MethodNode methodNode, MethodInsnNode minsn, boolean stable) { + SourceValueInterpreter i = MethodAnalyzer.analyzeInterpretMethod(methodNode, new SourceValueInterpreter(minsn, stable)); return i.getResults(); } - private static class SourceValueInterpreter extends SourceInterpreter { + private static class SourceValueInterpreter extends AdvancedSourceInterpreter { private final AbstractInsnNode targetInsn; private List results; - public SourceValueInterpreter(AbstractInsnNode targetInsn) { - super(Opcodes.ASM9); + public SourceValueInterpreter(AbstractInsnNode targetInsn, boolean stable) { + super(stable); this.targetInsn = targetInsn; } diff --git a/core/src/main/java/org/sinytra/adapter/analysis/selector/FrameUtil.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/FrameUtil.java index 8c4a75d2..28333d9c 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/selector/FrameUtil.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/selector/FrameUtil.java @@ -1,6 +1,7 @@ package org.sinytra.adapter.analysis.selector; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.MethodInsnNode; @@ -9,6 +10,7 @@ import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; +import org.sinytra.adapter.analysis.method.AdvancedSourceInterpreter; public class FrameUtil { public static Frame[] getFrames(MethodNode methodNode) { @@ -20,6 +22,15 @@ public static Frame[] getFrames(MethodNode methodNode) { } } + public static Frame[] getStableFrames(MethodNode methodNode) { + try { + Analyzer analyzer = new Analyzer<>(new AdvancedSourceInterpreter(true)); + return analyzer.analyze(Object.class.getName(), methodNode); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + // Helper to determine how many stack items an instruction consumes public static int getPopCount(AbstractInsnNode insn) { int op = insn.getOpcode(); @@ -28,7 +39,7 @@ public static int getPopCount(AbstractInsnNode insn) { if (insn instanceof MethodInsnNode) { // Static: pops args // Virtual/Special/Interface: pops args + receiver (1) - int args = org.objectweb.asm.Type.getArgumentsAndReturnSizes(((MethodInsnNode) insn).desc) >> 2; + int args = Type.getArgumentsAndReturnSizes(((MethodInsnNode) insn).desc) >> 2; boolean isStatic = op == Opcodes.INVOKESTATIC; // INVOKEDYNAMIC is complex, but usually acts like static for the bootstrap if (op == org.objectweb.asm.Opcodes.INVOKEDYNAMIC) isStatic = true; diff --git a/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java index f32fdb61..cafb21d6 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java +++ b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java @@ -25,7 +25,7 @@ public static Multimap methodTransformers(List transformers) { + this.classTransformers.addAll(transformers); + return this; + } + public Builder methodTransformer(TxPhase phase, MethodTransformer transformer) { this.methodTransformers.put(phase, transformer); return this; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java index 7a451230..face8612 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java @@ -12,8 +12,6 @@ public class PropertyProcessor implements Processor { @Override public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { - if (dirty.getAtData() == null) return TxResult.FAIL; - // TODO Auto append all props AnnotationHandle handle = context.methodAnnotation(); dirty.getProperty(ORDINAL) diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpAnalyzer.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpAnalyzer.java index ccad6f9d..55418002 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpAnalyzer.java @@ -17,7 +17,7 @@ public class WrapOpAnalyzer { public static List> groupArrayInitializers(MethodNode methodNode, AbstractInsnNode newArrayInsn) { // 1. Analyze the method frames to track data flow - Frame[] frames = FrameUtil.getFrames(methodNode); + Frame[] frames = FrameUtil.getStableFrames(methodNode); // Map to hold the AASTORE instruction for each array index // Key = Array Index (0, 1...), Value = The AASTORE instruction node diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java index 486b3177..bb78a4e3 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java @@ -49,13 +49,10 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe AbstractInsnNode dirtyInsn = context.methods().findInjectionTargetInsn(recipe.getDirtyTarget()); if (cleanInsn instanceof MethodInsnNode cleanMinsn && dirtyInsn instanceof MethodInsnNode dirtyMinsn) { List methodParams = dirty.getParameters().getTypes(MethodParameters.ParamGroup.METHOD_PARAMS); - boolean result = WrapOpSurgeon.tryUpgrade(context, recipe, methodParams, cleanMinsn, dirtyMinsn); - if (!result) { - return TxResult.FAIL; - } + WrapOpSurgeon.tryUpgrade(context, recipe, methodParams, cleanMinsn, dirtyMinsn); } - return TxResult.PASS; + return TxResult.SUCCESS; } @Nullable diff --git a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java index 696383d0..2dc5c4bf 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java @@ -36,9 +36,11 @@ public class PipelineMethodTransformer implements MethodTransformer { private static final Logger LOGGER = LogUtils.getLogger(); private final List methodPatches; + private final boolean patchesOnly; - public PipelineMethodTransformer(List methodPatches) { + public PipelineMethodTransformer(List methodPatches, boolean patchesOnly) { this.methodPatches = methodPatches; + this.patchesOnly = patchesOnly; } @Override @@ -66,7 +68,7 @@ public PatchResult apply(MixinContext context, Configuration config) { private PatchResult execute(MixinContext context, Configuration config) { String mixinId = context.getMixinId(); - Resolvers resolvers = context.getResolvers(); + Resolvers resolvers = this.patchesOnly ? new Resolvers(false) : context.getResolvers(); Processors processors = context.getProcessors(); // 0. Add highest priority manual patch resolver diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/ConfigurationMatcher.java b/core/src/main/java/org/sinytra/adapter/transform/patch/ConfigurationMatcher.java index d7b31afa..4c2cb7de 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/ConfigurationMatcher.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/ConfigurationMatcher.java @@ -18,7 +18,7 @@ private ConfigurationMatcher(Map, Predicate> matchers) { @SuppressWarnings({"rawtypes", "unchecked"}) public boolean match(PropertyContainer container) { for (Map.Entry, Predicate> entry : this.matchers.entrySet()) { - Object value = container.getProperty(entry.getKey()); + Object value = container.getProperty(entry.getKey()).orElse(null); if (value == null || !((Predicate) entry.getValue()).test(value)) { return false; } diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java index cd89baee..22031326 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java @@ -1,9 +1,11 @@ package org.sinytra.adapter.transform.patch; import org.objectweb.asm.commons.InstructionAdapter; +import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.transform.MethodTransformer; import java.util.function.Consumer; +import java.util.function.UnaryOperator; public interface MethodPatchBuilder { // Matching @@ -32,6 +34,8 @@ public interface MethodPatchBuilder { MethodPatchBuilder modifyInjectionPoint(String value, String target); MethodPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues); + + MethodPatchBuilder modifyParams(UnaryOperator op); // TODO This should be automatic MethodPatchBuilder modifyStatic(boolean isStatic); @@ -43,4 +47,6 @@ public interface MethodPatchBuilder { MethodPatchBuilder disable(); MethodPatchBuilder transform(MethodTransformer transformer); + + MethodPatch build(); } diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java index e8361705..8e76f3dd 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java @@ -2,6 +2,7 @@ import org.objectweb.asm.commons.InstructionAdapter; import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.SpecialKeys; import org.sinytra.adapter.transform.MethodTransformer; @@ -11,6 +12,7 @@ import java.util.List; import java.util.OptionalDouble; import java.util.function.Consumer; +import java.util.function.UnaryOperator; import java.util.stream.Stream; import static java.util.function.Predicate.isEqual; @@ -21,7 +23,8 @@ public class MethodPatchBuilderImpl implements MethodPatchBuilder { private final MutableConfiguration config = MutableConfiguration.create(); private final List transforms = new ArrayList<>(); - public MethodPatchImpl build() { + @Override + public MethodPatch build() { ConfigurationMatcher finalMatcher = this.matcher.build(); return new MethodPatchImpl(finalMatcher, this.config, this.transforms); } @@ -107,6 +110,12 @@ public MethodPatchBuilder modifyInjectionPoint(String value, String target, bool return this; } + @Override + public MethodPatchBuilder modifyParams(UnaryOperator op) { + + return this; + } + @Override public MethodPatchBuilder modifyStatic(boolean isStatic) { this.config.setProperty(SpecialKeys.STATIC, isStatic); diff --git a/core/src/main/java/org/sinytra/adapter/types/FieldTypeUsageTransformer.java b/core/src/main/java/org/sinytra/adapter/types/FieldTypeUsageTransformer.java index e7185c77..b647de8f 100644 --- a/core/src/main/java/org/sinytra/adapter/types/FieldTypeUsageTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/types/FieldTypeUsageTransformer.java @@ -38,6 +38,7 @@ public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchCont field.desc = updatedTypes.getSecond().getDescriptor(); // Update shadow field usages classUpdatedTypes.put(field.name, updatedTypes); + applied = true; } } } 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 77c61041..18b1b34c 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 @@ -6,6 +6,7 @@ import org.junit.jupiter.api.Test; import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.ctx.RefmapHolder; import org.sinytra.adapter.patch.DynamicPatches; import org.sinytra.adapter.patch.Patcher; @@ -16,6 +17,8 @@ import java.util.List; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + public class DynamicMixinPatchTest extends MinecraftMixinPatchTest { private static final Logger LOGGER = LogUtils.getLogger(); @@ -429,7 +432,8 @@ void testSyntheticInstanceofMEV() throws Exception { protected LoadResult load(String className, List allowedMethods) throws Exception { ClassNode patched = loadClass(className); patched.methods.removeIf(m -> !allowedMethods.contains(m.name)); - patcher.process(patched); + PatchResult result = patcher.process(patched); + assertNotEquals(PatchResult.PASS, result); return new LoadResult(patchEnvironment, patched, loadClass(className)); } } From 74b31417f0389e24c620bfd9816ecb1921b0beae Mon Sep 17 00:00:00 2001 From: Su5eD Date: Fri, 30 Jan 2026 13:57:35 +0100 Subject: [PATCH 11/27] Patch method calls in redirect --- .../analysis/method/MethodCallAnalyzer.java | 2 +- .../params/LayeredParamsDiffSnapshot.java | 5 ++ .../analysis/params/ParamsDiffSnapshot.java | 2 + .../analysis/selector/AnnotationHandle.java | 2 +- .../org/sinytra/adapter/env/ann/AtData.java | 8 +-- .../sinytra/adapter/env/ann/ConstantData.java | 50 ++++++++----------- .../sinytra/adapter/env/ctx/MethodHelper.java | 31 ++++++++++-- .../patch/config/BasePropertyContainer.java | 9 ++++ .../sinytra/adapter/patch/config/Keys.java | 2 + .../patch/config/PropertyContainer.java | 4 ++ .../processor/InjectionTargetProcessor.java | 11 ++-- .../patch/processor/ParametersProcessor.java | 2 + .../redirect/ParameterUsageProcessor.java | 49 +++++++++++++++--- .../wrapop/WrapOpParamsProcessor.java | 14 +++--- .../ArbitraryInjectionPointSubResolver.java | 8 +-- .../patch/MethodPatchBuilderImpl.java | 8 +-- .../transform/patch/MethodPatchResolver.java | 6 +++ .../test/mixin/DynamicMixinPatchTest.java | 6 +-- .../mixin/pipeline/ClientLanguageMixin.java | 34 +++++++------ 19 files changed, 165 insertions(+), 88 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java index e6b8b0d4..681fa9cd 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java @@ -35,8 +35,8 @@ public static List> getAllMethodCallSrcInsnsInclusive(Met for (AbstractInsnNode insn : methodNode.instructions) { if (insn instanceof MethodInsnNode minsn && qualifier.matches(minsn)) { List insns = getMethodCallSrcInsns(methodNode, minsn, true); - insns.add(minsn); if (insns != null) { + insns.add(minsn); list.add(insns); } } diff --git a/core/src/main/java/org/sinytra/adapter/analysis/params/LayeredParamsDiffSnapshot.java b/core/src/main/java/org/sinytra/adapter/analysis/params/LayeredParamsDiffSnapshot.java index b8763f02..c51d8ae7 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/params/LayeredParamsDiffSnapshot.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/LayeredParamsDiffSnapshot.java @@ -144,6 +144,11 @@ public ParameterTransformer asParameterTransformer(Set flags) { } } + @Override + public int modificationsCount() { + return this.modifications.size(); + } + @Override public boolean isEmpty() { return this.modifications.isEmpty(); diff --git a/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshot.java b/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshot.java index f7ed70c6..efb7c050 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshot.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/ParamsDiffSnapshot.java @@ -14,6 +14,8 @@ enum Flags { REMOVED_VAR_GRAVE } + int modificationsCount(); + boolean isEmpty(); List> insertions(); diff --git a/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java index 6abccffa..fd8a5444 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java @@ -10,7 +10,7 @@ public final class AnnotationHandle { private final Map> handleCache = new HashMap<>(); public AnnotationHandle(AnnotationNode annotationNode) { - this.annotationNode = annotationNode; + this.annotationNode = Objects.requireNonNull(annotationNode); } public String getDesc() { diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java index f5b95ca9..2b2d233e 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java @@ -3,13 +3,13 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.env.ctx.RefMapper; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.config.MutablePropertyContainer; import org.sinytra.adapter.patch.config.PropertyContainer; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; import org.sinytra.adapter.patch.config.PropertyKey; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.util.MethodQualifier; import org.spongepowered.asm.mixin.injection.At; @@ -48,12 +48,8 @@ public Optional getOrdinal() { return getProperty(Keys.ORDINAL); } - @SuppressWarnings({"rawtypes", "unchecked"}) public void apply(AnnotationHandle handle) { - this.properties.getProperties().forEach((key, value) -> { - Object serialized = ((PropertyKey) key).serialize(value); - handle.setOrAppendNonNull(key.name(), serialized); - }); + this.properties.apply(handle); } public AnnotationNode toAnnotationNode() { diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java b/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java index e47993b6..429c7d94 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java @@ -2,50 +2,44 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.patch.config.MutablePropertyContainer; +import org.sinytra.adapter.patch.config.PropertyContainer; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.PropertyKey; -import java.util.List; import java.util.Optional; -import java.util.OptionalDouble; -// TODO Cleanup public class ConstantData { - private final Object value; + private static final PropertyContainerTemplate TEMPLATE = PropertyContainerTemplate.builder() + .requireOne(Keys.DOUBLE_VALUE, Keys.CLASS_VALUE) + .build(); - private ConstantData(Object value) { - this.value = value; - } + private final PropertyContainer properties; - public Optional classValue() { - return value instanceof Type t ? Optional.of(t) : Optional.empty(); + private ConstantData(PropertyContainer properties) { + this.properties = properties; } - public OptionalDouble doubleValue() { - return value instanceof Double d ? OptionalDouble.of(d) : OptionalDouble.empty(); + public Optional doubleValue() { + return this.properties.getProperty(Keys.DOUBLE_VALUE); } public static ConstantData classValue(Type value) { - return new ConstantData(value); + PropertyContainer container = MutablePropertyContainer.create().setProperty(Keys.CLASS_VALUE, value); + return new ConstantData(container); } public void apply(AnnotationHandle handle) { - if (this.value instanceof Type) { - handle.setOrAppendNonNull("classValue", this.value); - } else if (this.value instanceof Double) { - handle.setOrAppendNonNull("doubleValue", this.value); - } else { - throw new IllegalStateException("Unexpected value: " + value); - } + this.properties.apply(handle); } public static Optional parse(AnnotationHandle handle) { - List knownKeys = List.of("doubleValue", "classValue"); - for (String key : knownKeys) { - Object value = handle.getValue(key).map(AnnotationValueHandle::get).orElse(null); - if (value != null) { - return Optional.of(new ConstantData(value)); - } - } - return Optional.empty(); + MutablePropertyContainer container = MutablePropertyContainer.parseValid(handle, TEMPLATE, s -> s); + return Optional.ofNullable(container).map(ConstantData::new); + } + + public static class Keys { + public static final PropertyKey DOUBLE_VALUE = PropertyKey.create("doubleValue", Double.class); + public static final PropertyKey CLASS_VALUE = PropertyKey.create("classValue", Type.class); } } diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java index 9b12d406..9baa5ed1 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java @@ -6,16 +6,17 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.MockMixinRuntime; +import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.param.ParamDiffResolver; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; -import org.sinytra.adapter.env.MockMixinRuntime; import org.sinytra.adapter.util.provider.ClassLookup; import org.slf4j.Logger; import org.spongepowered.asm.mixin.injection.InjectionPoint; @@ -112,6 +113,28 @@ private List computeInjectionTargetInsns(@Nullable TargetPair ); } + // TODO Always use config AtData? + @Nullable + public AbstractInsnNode findInjectionTargetInsn(@Nullable TargetPair target, AtData atData) { + List cleanInsns = findInjectionTargetInsns(target, atData); + return cleanInsns.size() != 1 ? null : cleanInsns.getFirst(); + } + + public List findInjectionTargetInsns(@Nullable TargetPair target, AtData atData) { + return computeInjectionTargetInsns( + target, + this.context::injectionPointAnnotation, + (ctx, h) -> { + AnnotationNode atCopy = atData.toAnnotationNode(); + AnnotationHandle annCopy = this.context.methodAnnotation().copy(); + annCopy.setOrAppendNonNull(PROPERTY_AT, atCopy); + + return InjectionPoint.parse(ctx, this.context.methodNode(), annCopy.unwrap(), atCopy); + }, + true + ); + } + public List resolveCapturedMethodParams(Configuration clean, Configuration dirty) { List cleanCaptured = clean.getParameters().getTypes(CAPTURED_PARAMS); List dirtyCaptured = new ArrayList<>(); diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java index b2b6c473..594ee914 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java @@ -73,6 +73,15 @@ public MutablePropertyContainer mergeFrom(PropertyContainer other) { return this; } + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void apply(AnnotationHandle handle) { + this.properties.forEach((key, value) -> { + Object serialized = ((PropertyKey) key).serialize(value); + handle.setOrAppendNonNull(key.name(), serialized); + }); + } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java b/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java index 192c6c99..6b414258 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java @@ -34,6 +34,8 @@ public final class Keys { public static final PropertyKey TARGET_AT = PropertyKey.builder("at") .parser((value, mapper) -> { AnnotationNode node = parseSingle(value, AnnotationNode.class); + if (node == null) return null; + AnnotationHandle handle = new AnnotationHandle(node); return AtData.parse(handle, mapper).orElse(null); }) diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainer.java index 140ab1ca..87fa4f04 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainer.java @@ -1,5 +1,7 @@ package org.sinytra.adapter.patch.config; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; + import java.util.Map; import java.util.Optional; @@ -13,4 +15,6 @@ public interface PropertyContainer { MutablePropertyContainer copy(); boolean validate(); + + void apply(AnnotationHandle handle); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java index 29d01a55..a1e8f7c8 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java @@ -17,22 +17,21 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe return TxResult.PASS; } - AnnotationHandle annotation = context.methodAnnotation(); + AnnotationHandle annotation = context.methodAnnotation(); + + annotation.removeValues(MixinAnnotationConstants.PROPERTY_AT); if (dirty.getAtData() != null) { AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_AT, MixinAnnotations.AT); dirty.getAtData().apply(handle); - } else { - annotation.removeValues(MixinAnnotationConstants.PROPERTY_AT); } + annotation.removeValues(MixinAnnotationConstants.PROPERTY_CONSTANT); if (dirty.hasProperty(Keys.TARGET_CONSTANT)) { AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_CONSTANT, MixinAnnotations.CONSTANT); ConstantData cst = dirty.getProperty(Keys.TARGET_CONSTANT).orElseThrow(); cst.apply(handle); - } else { - annotation.removeValues(MixinAnnotationConstants.PROPERTY_CONSTANT); } - + // methodContext.recordAudit(this, "Change injection point to %s", this.target); return TxResult.SUCCESS; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java index 2001dcb9..91310d5d 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java @@ -50,6 +50,8 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe Parameters.applyVarMappings(context.methodNode(), oldVarMap); Parameters.applyAnnotations(context.methodNode(), dirtyParams.merge()); + context.methodNode().maxLocals = context.methodNode().localVariables.size(); + return TxResult.SUCCESS; } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java index 7770d18e..1a312cd4 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java @@ -1,14 +1,25 @@ package org.sinytra.adapter.patch.processor.redirect; +import com.mojang.datafixers.util.Pair; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodInsnNode; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters.ParamGroup; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.processor.Processor; +import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; +import java.util.List; + public class ParameterUsageProcessor implements Processor { @Override public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { @@ -19,13 +30,37 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe MethodQualifier cleanTargetQual = MethodQualifier.parse(cleanTarget).orElseThrow(); MethodQualifier dirtyTargetQual = MethodQualifier.parse(dirtyTarget).orElseThrow(); - for (AbstractInsnNode insn : context.methodNode().instructions) { - if (insn instanceof MethodInsnNode minsn && cleanTargetQual.matches(minsn)) { - if (dirtyTargetQual.owner() != null) { - minsn.owner = dirtyTargetQual.internalOwnerName(); - } - minsn.name = dirtyTargetQual.name(); - minsn.desc = dirtyTargetQual.desc(); + + List cleanParams = recipe.clean().getParameters().getTypes(ParamGroup.METHOD_PARAMS); + List dirtyParams = recipe.dirty().getParameters().getTypes(ParamGroup.METHOD_PARAMS); + ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(cleanParams, dirtyParams); + + List> callInsns = MethodCallAnalyzer.getAllMethodCallSrcInsnsInclusive(context.methodNode(), cleanTargetQual); + if (callInsns.isEmpty()) { + return TxResult.SUCCESS; + } + + LocalVariableLookup lookup = new LocalVariableLookup(context.methodNode()); + for (List call : callInsns) { + MethodInsnNode minsn = (MethodInsnNode) call.getLast(); + + // Update call target + if (dirtyTargetQual.owner() != null) { + minsn.owner = dirtyTargetQual.internalOwnerName(); + } + minsn.name = dirtyTargetQual.name(); + minsn.desc = dirtyTargetQual.desc(); + + // TODO Helper class like for WrapOp + // Insert new params + for (Pair insertion : diff.insertions()) { + int ordinal = insertion.getFirst(); + LocalVariableNode node = lookup.getByParameterOrdinal(ordinal); + + AbstractInsnNode nextInsn = call.get(ordinal); + AbstractInsnNode insn = AdapterUtil.loadType(insertion.getSecond(), node.index); + context.methodNode().instructions.insertBefore(nextInsn, insn); + call.add(ordinal, insn); } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java index bb78a4e3..e723af16 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java @@ -44,12 +44,14 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe } } - // Upgrade calls on "instance" variable - AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(recipe.getCleanTarget()); - AbstractInsnNode dirtyInsn = context.methods().findInjectionTargetInsn(recipe.getDirtyTarget()); - if (cleanInsn instanceof MethodInsnNode cleanMinsn && dirtyInsn instanceof MethodInsnNode dirtyMinsn) { - List methodParams = dirty.getParameters().getTypes(MethodParameters.ParamGroup.METHOD_PARAMS); - WrapOpSurgeon.tryUpgrade(context, recipe, methodParams, cleanMinsn, dirtyMinsn); + if (dirty.getAtData() != null) { + // Upgrade calls on "instance" variable + AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(recipe.getCleanTarget()); + AbstractInsnNode dirtyInsn = context.methods().findInjectionTargetInsn(recipe.getDirtyTarget(), dirty.getAtData()); + if (cleanInsn instanceof MethodInsnNode cleanMinsn && dirtyInsn instanceof MethodInsnNode dirtyMinsn) { + List methodParams = dirty.getParameters().getTypes(MethodParameters.ParamGroup.METHOD_PARAMS); + WrapOpSurgeon.tryUpgrade(context, recipe, methodParams, cleanMinsn, dirtyMinsn); + } } return TxResult.SUCCESS; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java index ea8bcd59..5693a576 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java @@ -28,7 +28,7 @@ public class ArbitraryInjectionPointSubResolver implements SubResolver { @Nullable @Override public Configuration resolve(MixinContext context, Recipe recipe) { - String injectionPointTarget = recipe.clean().getAtData().getTarget().orElseThrow(); + String injectionPointTarget = recipe.clean().getAtData().getTarget().orElse(null); TargetPair cleanTarget = recipe.getCleanTarget(); TargetPair dirtyTarget = recipe.getDirtyTarget(); AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanTarget); @@ -52,7 +52,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { return MutableConfiguration.create().setAtData(AtData.create(AT_VAL_INVOKE, targetMethodCall)); } - private MethodInsnNode resolveTargetCallInsn(MethodNode dirtyTargetMethod, AbstractInsnNode cleanInjectionInsn, MixinContext context, String injectionPointTarget) { + private MethodInsnNode resolveTargetCallInsn(MethodNode dirtyTargetMethod, AbstractInsnNode cleanInjectionInsn, MixinContext context, @Nullable String injectionPointTarget) { AbstractInsnNode nextCallCandidate = findCandidates(MethodInsnMatcher.findBackwardsInstructions(cleanInjectionInsn).inverse(), dirtyTargetMethod, List::getLast); if (nextCallCandidate != null) { @@ -91,10 +91,10 @@ private static AbstractInsnNode findCandidates(InstructionMatcher cleanMatcher, return !candidates.isEmpty() ? candidates.getFirst() : null; } - private static MethodInsnNode findReplacementInjectionPoint(AbstractInsnNode lastInsn, UnaryOperator flow, MixinContext context, String injectionPointTarget) { + private static MethodInsnNode findReplacementInjectionPoint(AbstractInsnNode lastInsn, UnaryOperator flow, MixinContext context, @Nullable String injectionPointTarget) { // Require matching return types for ModifyExpressionValue mixins // TODO Eliminate use of matchesDesc - if (context.methodAnnotation().matchesDesc(MixinAnnotations.MODIFY_EXPR_VAL)) { + if (context.methodAnnotation().matchesDesc(MixinAnnotations.MODIFY_EXPR_VAL) && injectionPointTarget != null) { Type desiredReturnType = Type.getReturnType(injectionPointTarget); return (MethodInsnNode) AdapterUtil.iterateInsns(lastInsn, flow, v -> v instanceof MethodInsnNode minsn && Type.getReturnType(minsn.desc).equals(desiredReturnType)); diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java index 8e76f3dd..9c3cb297 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java @@ -10,7 +10,7 @@ import java.util.ArrayList; import java.util.List; -import java.util.OptionalDouble; +import java.util.Optional; import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.stream.Stream; @@ -45,7 +45,7 @@ public MethodPatchBuilder targetClass(String... targets) { public MethodPatchBuilder targetMethod(String... targets) { Stream.of(targets) .map(t -> MethodQualifier.parse(t).orElseThrow()) - .forEach(t -> this.matcher.match(TARGET_METHOD, q -> q.matches(t))); + .forEach(t -> this.matcher.match(TARGET_METHOD, t::matches)); return this; } @@ -65,8 +65,8 @@ public MethodPatchBuilder targetInjectionPoint(String value, String target) { public MethodPatchBuilder targetConstant(double doubleValue) { this.matcher.match(TARGET_CONSTANT, c -> { // TODO OR check at const value - OptionalDouble opt = c.doubleValue(); - return opt.isPresent() && opt.getAsDouble() == doubleValue; + Optional opt = c.doubleValue(); + return opt.isPresent() && opt.get() == doubleValue; }); return this; } diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java index 1a5a18bb..95b455a4 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java @@ -3,6 +3,7 @@ import org.sinytra.adapter.env.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.Configurations; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.resolver.Resolver; import org.sinytra.adapter.transform.MethodTransformer; @@ -39,6 +40,11 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { // TODO Might get cancelled by earlier processor recipe.processors().add(new MethodPatchProcessor(postChanges)); } + + // TODO Ugly hardcoding + if (dirtyConfig.shouldDelete()) { + return ResolutionResult.replace(Configurations.DELETE); + } return ResolutionResult.replace(dirtyConfig); } 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 18b1b34c..77c61041 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 @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test; import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.env.ctx.PatchEnvironment; -import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.ctx.RefmapHolder; import org.sinytra.adapter.patch.DynamicPatches; import org.sinytra.adapter.patch.Patcher; @@ -17,8 +16,6 @@ import java.util.List; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - public class DynamicMixinPatchTest extends MinecraftMixinPatchTest { private static final Logger LOGGER = LogUtils.getLogger(); @@ -432,8 +429,7 @@ void testSyntheticInstanceofMEV() throws Exception { protected LoadResult load(String className, List allowedMethods) throws Exception { ClassNode patched = loadClass(className); patched.methods.removeIf(m -> !allowedMethods.contains(m.name)); - PatchResult result = patcher.process(patched); - assertNotEquals(PatchResult.PASS, result); + patcher.process(patched); return new LoadResult(patchEnvironment, patched, loadClass(className)); } } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ClientLanguageMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ClientLanguageMixin.java index d418882c..e86c1f15 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ClientLanguageMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ClientLanguageMixin.java @@ -1,11 +1,14 @@ package org.sinytra.adapter.test.mixin.pipeline; +import com.google.common.collect.Maps; import net.minecraft.client.resources.language.ClientLanguage; +import net.minecraft.locale.Language; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import java.io.InputStream; +import java.util.Map; import java.util.function.BiConsumer; @Mixin(ClientLanguage.class) @@ -18,14 +21,13 @@ public class ClientLanguageMixin { ) ) private static void saveSeparately(InputStream inputStream, BiConsumer entryConsumer, String langCode) { - // TODO Patch code as well -// Map> map = Maps.newHashMap(); -// -// Language.loadFromJson(inputStream, entryConsumer.andThen((key, value) -> -// map.computeIfAbsent(langCode, k -> Maps.newHashMap()) -// .put(key, value))); -// -// Language.loadFromJson(inputStream, entryConsumer); + Map> map = Maps.newHashMap(); + + Language.loadFromJson(inputStream, entryConsumer.andThen((key, value) -> + map.computeIfAbsent(langCode, k -> Maps.newHashMap()) + .put(key, value))); + + Language.loadFromJson(inputStream, entryConsumer); } @Redirect( @@ -36,13 +38,13 @@ private static void saveSeparately(InputStream inputStream, BiConsumer entryCons ) ) private static void saveSeparatelyExpected(InputStream inputStream, BiConsumer entryConsumer, BiConsumer adapter_injected_2, String langCode) { -// Map> map = Maps.newHashMap(); -// -// Language.loadFromJson(inputStream, entryConsumer.andThen((key, value) -> -// map.computeIfAbsent(langCode, k -> Maps.newHashMap()) -// .put(key, value)), consumer); // Added consumer arg -// -// // Added consumer arg -// Language.loadFromJson(inputStream, entryConsumer, consumer); + Map> map = Maps.newHashMap(); + + Language.loadFromJson(inputStream, entryConsumer.andThen((key, value) -> + map.computeIfAbsent(langCode, k -> Maps.newHashMap()) + .put(key, value)), adapter_injected_2); // Added consumer arg + + // Added consumer arg + Language.loadFromJson(inputStream, entryConsumer, adapter_injected_2); } } From 98324e813e3bf63c6a3b0dd810475b5b678b7552 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Fri, 30 Jan 2026 18:38:40 +0100 Subject: [PATCH 12/27] Cleanup TODOs --- .../analysis/locals/LocalVarAnalyzer.java | 2 +- .../analysis/locals/LocalVariableLookup.java | 4 +- .../analysis/params/EnhancedParamsDiff.java | 6 +- .../analysis/selector/AnnotationHandle.java | 33 +------ .../analysis/selector/FieldMatcher.java | 27 ------ .../org/sinytra/adapter/env/ann/AtData.java | 8 +- .../sinytra/adapter/env/ann/ClassTarget.java | 1 - .../sinytra/adapter/env/ann/ConstantData.java | 8 ++ .../sinytra/adapter/env/ctx/AuditTrail.java | 1 - .../adapter/env/ctx/AuditTrailImpl.java | 5 +- .../sinytra/adapter/env/ctx/MethodFinder.java | 8 +- .../sinytra/adapter/env/ctx/MethodHelper.java | 20 ++--- .../adapter/env/{ => ctx}/MixinContext.java | 15 +++- .../sinytra/adapter/env/ctx/PatchContext.java | 4 +- .../adapter/env/ctx/PatchEnvironment.java | 2 +- .../adapter/env/ctx/PatchEnvironmentImpl.java | 85 ++++++++++++++++--- .../env/util/MixinAnnotationConstants.java | 8 +- .../sinytra/adapter/patch/DynamicPatches.java | 2 +- .../sinytra/adapter/patch/MixinParser.java | 10 ++- .../org/sinytra/adapter/patch/Patcher.java | 15 ++-- .../org/sinytra/adapter/patch/Recipe.java | 2 +- .../patch/config/BasePropertyContainer.java | 6 +- .../patch/config/ConfigurationImpl.java | 52 +++++++----- .../patch/config/ConfigurationTemplates.java | 11 ++- .../patch/config/MutableConfiguration.java | 2 + .../config/MutablePropertyContainer.java | 2 +- .../adapter/patch/config/PropertyKey.java | 15 +++- .../adapter/patch/config/key/ControlKeys.java | 33 +++++++ .../config/{Keys.java => key/MixinKeys.java} | 47 ++++------ .../patch/config/{ => key}/SpecialKeys.java | 6 +- .../adapter/patch/mixin/InjectMixin.java | 6 +- .../adapter/patch/mixin/MixinFlag.java | 20 +++++ .../adapter/patch/mixin/MixinType.java | 9 +- .../adapter/patch/mixin/ModifyArgMixin.java | 13 ++- .../mixin/ModifyExpressionValueMixin.java | 13 ++- .../patch/mixin/ModifyReturnValueMixin.java | 2 +- .../patch/mixin/ModifyVariableMixin.java | 15 ++-- .../adapter/patch/mixin/RedirectMixin.java | 19 +++-- .../patch/mixin/WrapOperationMixin.java | 18 ++-- .../processor/DisableMixinProcessor.java | 2 +- .../processor/InjectionTargetProcessor.java | 39 --------- .../patch/processor/MixinTypeProcessor.java | 2 +- .../patch/processor/ParametersProcessor.java | 2 +- .../adapter/patch/processor/Processor.java | 2 +- .../adapter/patch/processor/Processors.java | 14 ++- .../patch/processor/PropertyProcessor.java | 37 ++++++-- .../patch/processor/ReturnTypeProcessor.java | 2 +- .../processor/StaticAccessProcessor.java | 4 +- .../processor/TargetMethodProcessor.java | 11 +-- .../extract/ExtractMixinProcessor.java | 10 +-- .../extract/MirrorableExtractMixin.java | 2 +- .../redirect/DivertRedirectProcessor.java | 4 +- .../redirect/ParameterUsageProcessor.java | 2 +- .../wrapop/WrapOpParamsProcessor.java | 2 +- .../patch/processor/wrapop/WrapOpSurgeon.java | 6 +- .../patch/resolver/CompoundResolver.java | 2 +- .../adapter/patch/resolver/Resolver.java | 2 +- .../adapter/patch/resolver/SubResolver.java | 2 +- .../ArbitraryInjectionPointSubResolver.java | 15 ++-- .../AtVariableAssignStoreSubResolver.java | 12 ++- .../ComparingInjectionPointResolver.java | 13 ++- .../InheritedInjectionPointSubResolver.java | 8 +- .../injection/InjectionPointResolver.java | 2 +- .../injection/InjectionPointSubResolvers.java | 2 +- .../ModifyVarInjectionPointSubResolver.java | 4 +- .../special/InjectorOrdinalResolver.java | 52 ++++++------ .../special/ModifyVarAtReturnResolver.java | 6 +- .../special/ModifyVarUpgradeResolver.java | 2 +- .../special/ResolverSyntheticInstanceof.java | 2 +- .../special/SliceBoundaryResolver.java | 4 +- .../target/SplitMethodCancellationHelper.java | 2 +- .../target/SplitTargetMethodSubResolver.java | 2 +- .../resolver/target/TargetMethodResolver.java | 2 +- .../target/TargetMethodSubResolvers.java | 2 +- .../adapter/transform/MethodTransformer.java | 2 +- .../transform/PipelineMethodTransformer.java | 9 +- .../cls/DynamicAnonClassIndexPatch.java | 38 +++------ .../param/InjectParameterTransform.java | 16 ++-- .../param/InlineParameterTransformer.java | 2 +- .../param/MoveParametersTransformer.java | 2 +- .../param/ParamTransformationUtil.java | 39 ++++----- .../transform/param/ParameterTransformer.java | 2 +- .../param/RemoveParameterTransformer.java | 2 +- .../param/ReplaceParametersTransformer.java | 4 +- .../param/SubstituteParameterTransformer.java | 2 +- .../param/SwapParametersTransformer.java | 2 +- .../transform/param/TransformParameters.java | 9 +- .../adapter/transform/patch/MethodPatch.java | 4 + .../transform/patch/MethodPatchBuilder.java | 2 +- .../patch/MethodPatchBuilderImpl.java | 38 ++++++--- .../transform/patch/MethodPatchImpl.java | 11 ++- .../transform/patch/MethodPatchProcessor.java | 2 +- .../transform/patch/MethodPatchResolver.java | 8 +- .../LocalCaptureUpgradeTransformer.java | 6 +- .../types/FieldAccessorTypeTransformer.java | 17 ++-- .../org/sinytra/adapter/util/AdapterUtil.java | 2 +- .../sinytra/adapter/util/MethodQualifier.java | 4 + 97 files changed, 577 insertions(+), 478 deletions(-) delete mode 100644 core/src/main/java/org/sinytra/adapter/analysis/selector/FieldMatcher.java rename core/src/main/java/org/sinytra/adapter/env/{ => ctx}/MixinContext.java (92%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/config/key/ControlKeys.java rename core/src/main/java/org/sinytra/adapter/patch/config/{Keys.java => key/MixinKeys.java} (67%) rename core/src/main/java/org/sinytra/adapter/patch/config/{ => key}/SpecialKeys.java (76%) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/mixin/MixinFlag.java delete mode 100644 core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java diff --git a/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVarAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVarAnalyzer.java index c3ca9952..c45744dd 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVarAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVarAnalyzer.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; diff --git a/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java index 430ecc36..fa480167 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java @@ -3,10 +3,10 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 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.env.ctx.MethodHelper; import java.util.*; @@ -17,7 +17,7 @@ public class LocalVariableLookup { private final Map> byType = new HashMap<>(); public LocalVariableLookup(MethodNode methodNode) { - this.isNonStatic = (methodNode.access & Opcodes.ACC_STATIC) == 0; + this.isNonStatic = !MethodHelper.isStatic(methodNode); this.sortedLocals = methodNode.localVariables.stream().sorted(Comparator.comparingInt(lvn -> lvn.index)).toList(); for (LocalVariableNode node : this.sortedLocals) { this.byIndex.put(node.index, node); diff --git a/core/src/main/java/org/sinytra/adapter/analysis/params/EnhancedParamsDiff.java b/core/src/main/java/org/sinytra/adapter/analysis/params/EnhancedParamsDiff.java index 253c3838..1f2cd61d 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/params/EnhancedParamsDiff.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/params/EnhancedParamsDiff.java @@ -5,10 +5,10 @@ import com.mojang.datafixers.util.Pair; 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.env.ctx.MethodHelper; import org.sinytra.adapter.util.GeneratedVariables; import org.slf4j.Logger; @@ -32,8 +32,8 @@ public static LayeredParamsDiffSnapshot compareMethodParameters(MethodNode clean 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; + boolean isCleanStatic = MethodHelper.isStatic(clean); + boolean isDirtyStatic = MethodHelper.isStatic(dirty); // Get params as local variables, which include their names as well List cleanParams = clean.localVariables.stream() .sorted(Comparator.comparingInt(lv -> lv.index)) diff --git a/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java index fd8a5444..65b9d9be 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/selector/AnnotationHandle.java @@ -6,7 +6,7 @@ import java.util.*; public final class AnnotationHandle { - private AnnotationNode annotationNode; + private final AnnotationNode annotationNode; private final Map> handleCache = new HashMap<>(); public AnnotationHandle(AnnotationNode annotationNode) { @@ -17,15 +17,11 @@ public String getDesc() { return this.annotationNode.desc; } - // TODO Remove me + @Deprecated public boolean matchesDesc(String desc) { return this.annotationNode.desc.equals(desc); } - public boolean matchesAny(Collection descs) { - return descs.stream().anyMatch(this.annotationNode.desc::equals); - } - public AnnotationNode unwrap() { return this.annotationNode; } @@ -52,13 +48,6 @@ public Optional getNested(String key) { .map(AnnotationHandle::new); } - public List getNestedList(String key) { - return this.>getValue(key).stream() - .flatMap(v -> v.get().stream()) - .map(AnnotationHandle::new) - .toList(); - } - @SuppressWarnings("unchecked") public Optional> getValue(String key) { AnnotationValueHandle handle = (AnnotationValueHandle) this.handleCache.computeIfAbsent(key, k -> AnnotationValueHandle.create(this.annotationNode, key).orElse(null)); @@ -90,24 +79,6 @@ public void appendValue(String key, Object value) { this.handleCache.remove(key); } - public Map> getAllValues() { - Map> map = new HashMap<>(); - if (this.annotationNode.values != null) { - for (int keyIdx = 0; keyIdx < this.annotationNode.values.size(); keyIdx += 2) { - String atKey = (String) this.annotationNode.values.get(keyIdx); - int valueIdx = keyIdx + 1; - AnnotationValueHandle existing = this.handleCache.compute(atKey, (k, v) -> v != null ? v : new AnnotationValueHandle<>(this.annotationNode.values, valueIdx, atKey)); - map.put(atKey, existing); - } - } - return map; - } - - public void refresh(AnnotationNode annotationNode) { - this.annotationNode = annotationNode; - this.handleCache.values().forEach(v -> v.refresh(annotationNode)); - } - public void setOrAppendNonNull(String key, @Nullable Object value) { if (value == null) { removeValues(key); diff --git a/core/src/main/java/org/sinytra/adapter/analysis/selector/FieldMatcher.java b/core/src/main/java/org/sinytra/adapter/analysis/selector/FieldMatcher.java deleted file mode 100644 index 727f96d3..00000000 --- a/core/src/main/java/org/sinytra/adapter/analysis/selector/FieldMatcher.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.sinytra.adapter.analysis.selector; - -import org.jetbrains.annotations.Nullable; - -public class FieldMatcher { - private final String name; - @Nullable - private final String desc; - - public FieldMatcher(String field) { - int descIndex = field.indexOf(':'); - this.name = descIndex == -1 ? field : field.substring(0, descIndex); - this.desc = descIndex == -1 ? null : field.substring(descIndex + 1); - } - - public String getName() { - return this.name; - } - - public boolean matches(FieldMatcher other) { - return matches(other.name, other.desc); - } - - public boolean matches(String name, String desc) { - return this.name.equals(name) && (this.desc == null || desc == null || this.desc.equals(desc)); - } -} diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java index 2b2d233e..c06bc2ee 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java @@ -58,6 +58,10 @@ public AnnotationNode toAnnotationNode() { return node; } + public AtData withValue(String value) { + return withProperty(Keys.VALUE, value); + } + public AtData withTarget(MethodInsnNode insn) { return withTarget(MethodQualifier.create(insn)); } @@ -100,7 +104,7 @@ public static Optional parse(AnnotationHandle annotation, RefMapper mapp public static AtData create(String value) { return builder(value).build(); } - + public static AtData create(String value, MethodInsnNode target) { return create(value, MethodQualifier.create(target).asDescriptor()); } @@ -123,7 +127,7 @@ public static class Builder { public Builder(String value) { this.properties.setProperty(Keys.VALUE, value); } - + public Builder target(String target) { return property(Keys.TARGET, target); } diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java index 791ea463..47b8cc3d 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java @@ -53,7 +53,6 @@ public Type getSingle() { return types.getFirst(); } - @Deprecated public void set(Type type) { this.either.ifLeft(h -> h.set(List.of(type))) .ifRight(h -> h.set(List.of(type.getInternalName()))); diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java b/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java index 429c7d94..753f8505 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ConstantData.java @@ -1,7 +1,9 @@ package org.sinytra.adapter.env.ann; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.config.MutablePropertyContainer; import org.sinytra.adapter.patch.config.PropertyContainer; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; @@ -33,6 +35,12 @@ public void apply(AnnotationHandle handle) { this.properties.apply(handle); } + public AnnotationNode toAnnotationNode() { + AnnotationNode node = new AnnotationNode(MixinAnnotations.AT); + this.properties.getProperties().forEach((key, value) -> node.visit(key.name(), value)); + return node; + } + public static Optional parse(AnnotationHandle handle) { MutablePropertyContainer container = MutablePropertyContainer.parseValid(handle, TEMPLATE, s -> s); return Optional.ofNullable(container).map(ConstantData::new); diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrail.java b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrail.java index 81ef0dfb..de6abe4f 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrail.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrail.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; import org.sinytra.adapter.patch.config.Configuration; import java.util.ArrayList; diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrailImpl.java b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrailImpl.java index e9eeaa79..a08ad530 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrailImpl.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/AuditTrailImpl.java @@ -5,9 +5,8 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.slf4j.Logger; import java.text.DecimalFormat; @@ -60,7 +59,7 @@ private void recordAudit(Object transform, @Nullable MethodNode methodNode, Cand public void recordResult(MixinContext context, Configuration configuration, Match match) { Candidate candidate = new Candidate(context.classNode(), context.methodNode()); this.candidates.compute(candidate, (key, prev) -> { - boolean isNotRequired = configuration.getProperty(Keys.REQUIRE) + boolean isNotRequired = configuration.getProperty(MixinKeys.REQUIRE) .map(i -> i == 0) .orElse(false); Match maybeIgnore = match == Match.NONE && isNotRequired ? Match.IGNORED : match; diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodFinder.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodFinder.java index 76c40529..caec2cc6 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodFinder.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodFinder.java @@ -7,7 +7,6 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.analysis.InheritanceHandler; import org.sinytra.adapter.util.MethodQualifier; import org.sinytra.adapter.util.provider.ClassLookup; import org.slf4j.Logger; @@ -24,10 +23,12 @@ public static class Flags { public static final int FALLBACK_OWNER = 0b10; } + private final PatchEnvironment environment; @Nullable private final String fallbackOwner; - public MethodFinder(String fallbackOwner) { + public MethodFinder(PatchEnvironment environment, String fallbackOwner) { + this.environment = environment; this.fallbackOwner = fallbackOwner; } @@ -36,8 +37,7 @@ public TargetPair findInheritedMethod(ClassLookup lookup, MethodQualifier qualif ClassNode node = lookup.getClass(qualifier.internalOwnerName()).orElse(null); if (node == null) return null; - // TODO Unify - Collection parents = new InheritanceHandler(lookup).getClassParents(node.name); + Collection parents = this.environment.inheritanceHandler(lookup).getClassParents(node.name); return Stream.concat(Stream.of(node.name), parents.stream()) .flatMap(cls -> lookup.findMethod(cls, qualifier.name(), qualifier.desc()).stream() diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java index 9baa5ed1..ddaa3a76 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java @@ -9,7 +9,6 @@ import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.analysis.params.LayeredParamsDiffSnapshot; import org.sinytra.adapter.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.env.MixinContext; import org.sinytra.adapter.env.MockMixinRuntime; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.param.ParamDiffResolver; @@ -46,7 +45,7 @@ public MethodHelper(MixinContext context, List targetTypes) { this.context = context; String singleTargetClass = targetTypes.size() == 1 ? targetTypes.getFirst().getInternalName() : null; - this.methodFinder = new MethodFinder(singleTargetClass); + this.methodFinder = new MethodFinder(context.environment(), singleTargetClass); } @Nullable @@ -93,11 +92,7 @@ public List findInjectionTargetInsns(@Nullable TargetPair targ } public List findInjectionTargetInsns(@Nullable TargetPair target, boolean ignoreOrdinal) { - return this.targetInstructionsCache.computeIfAbsent(target, t -> computeInjectionTargetInsns(t, ignoreOrdinal)); - } - - private List computeInjectionTargetInsns(@Nullable TargetPair target, boolean ignoreOrdinal) { - return computeInjectionTargetInsns( + return this.targetInstructionsCache.computeIfAbsent(target, t -> computeInjectionTargetInsns( target, this.context::injectionPointAnnotation, (ctx, h) -> { @@ -110,18 +105,12 @@ private List computeInjectionTargetInsns(@Nullable TargetPair return InjectionPoint.parse(ctx, this.context.methodNode(), this.context.methodAnnotation().unwrap(), atAnn.unwrap()); }, true - ); + )); } - // TODO Always use config AtData? @Nullable public AbstractInsnNode findInjectionTargetInsn(@Nullable TargetPair target, AtData atData) { - List cleanInsns = findInjectionTargetInsns(target, atData); - return cleanInsns.size() != 1 ? null : cleanInsns.getFirst(); - } - - public List findInjectionTargetInsns(@Nullable TargetPair target, AtData atData) { - return computeInjectionTargetInsns( + List cleanInsns = computeInjectionTargetInsns( target, this.context::injectionPointAnnotation, (ctx, h) -> { @@ -133,6 +122,7 @@ public List findInjectionTargetInsns(@Nullable TargetPair targ }, true ); + return cleanInsns.size() != 1 ? null : cleanInsns.getFirst(); } public List resolveCapturedMethodParams(Configuration clean, Configuration dirty) { diff --git a/core/src/main/java/org/sinytra/adapter/env/MixinContext.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java similarity index 92% rename from core/src/main/java/org/sinytra/adapter/env/MixinContext.java rename to core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java index fa418662..2ccc84ae 100644 --- a/core/src/main/java/org/sinytra/adapter/env/MixinContext.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java @@ -1,19 +1,20 @@ -package org.sinytra.adapter.env; +package org.sinytra.adapter.env.ctx; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.env.ann.ClassTarget; -import org.sinytra.adapter.env.ctx.*; +import org.sinytra.adapter.patch.mixin.MixinFlag; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.types.TypeAdapter; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.provider.ClassLookup; import java.util.List; +import java.util.Set; public class MixinContext implements RefMapper, Auditor { private final PatchContext patchContext; @@ -21,6 +22,7 @@ public class MixinContext implements RefMapper, Auditor { private final ClassNode classNode; private final MethodNode methodNode; private final MethodNode originalMethodNode; + private final Set flags; private final AnnotationHandle methodAnnotation; private final AnnotationHandle injectionPointAnnotation; @@ -30,13 +32,14 @@ public class MixinContext implements RefMapper, Auditor { private final Resolvers resolvers = new Resolvers(); private final Processors processors = new Processors(); - public MixinContext(PatchContext patchContext, ClassTarget classTarget, ClassNode classNode, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation) { + public MixinContext(PatchContext patchContext, ClassTarget classTarget, ClassNode classNode, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation, Set flags) { this.patchContext = patchContext; this.classTarget = classTarget; this.classNode = classNode; this.methodNode = methodNode; this.methodAnnotation = methodAnnotation; this.injectionPointAnnotation = injectionPointAnnotation; + this.flags = flags; this.methodHelper = new MethodHelper(this, classTarget.getTypes()); this.originalMethodNode = AdapterUtil.copyMethod(this.methodNode); @@ -44,6 +47,10 @@ public MixinContext(PatchContext patchContext, ClassTarget classTarget, ClassNod this.mixinId = classNode.name + "#" + methodNode.name + methodNode.desc; } + public boolean hasFlag(MixinFlag flag) { + return this.flags.contains(flag); + } + public String getMixinId() { return this.mixinId; } diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContext.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContext.java index a1a2c12b..293eb053 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContext.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchContext.java @@ -5,7 +5,7 @@ import java.util.List; -public interface PatchContext { +public interface PatchContext extends RefMapper { static PatchContext create(ClassNode classNode, List targetTypes, PatchEnvironment environment) { return new PatchContextImpl(classNode, targetTypes, environment); } @@ -16,7 +16,5 @@ static PatchContext create(ClassNode classNode, List targetTypes, PatchEnv PatchEnvironment environment(); - String remap(String reference); - void postApply(Runnable consumer); } diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironment.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironment.java index 416dbadb..8a96ef79 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironment.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironment.java @@ -23,7 +23,7 @@ static PatchEnvironment create(RefmapHolder refmapHolder, ClassLookup cleanClass @Nullable BytecodeFixerUpper bytecodeFixerUpper(); - InheritanceHandler inheritanceHandler(); + InheritanceHandler inheritanceHandler(ClassLookup lookup); RefmapHolder refmapHolder(); diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironmentImpl.java b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironmentImpl.java index 54518422..0ec8bf2a 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironmentImpl.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/PatchEnvironmentImpl.java @@ -6,21 +6,82 @@ import org.sinytra.adapter.util.provider.ClassLookup; import org.sinytra.adapter.util.provider.MixinClassLookup; -public record PatchEnvironmentImpl( - RefmapHolder refmapHolder, - ClassLookup cleanClassLookup, ClassLookup dirtyClassLookup, - @Nullable BytecodeFixerUpper bytecodeFixerUpper, - MixinClassGenerator classGenerator, - InheritanceHandler inheritanceHandler, - int fabricLVTCompatibility, - AuditTrail auditTrail -) implements PatchEnvironment { +import java.util.HashMap; +import java.util.Map; + +public final class PatchEnvironmentImpl implements PatchEnvironment { + private final RefmapHolder refmapHolder; + private final ClassLookup cleanClassLookup; + private final ClassLookup dirtyClassLookup; + private final @Nullable BytecodeFixerUpper bytecodeFixerUpper; + private final MixinClassGenerator classGenerator; + private final int fabricLVTCompatibility; + private final AuditTrail auditTrail; + + private final Map inheritanceHandlers = new HashMap<>(); + + public PatchEnvironmentImpl( + RefmapHolder refmapHolder, + ClassLookup cleanClassLookup, ClassLookup dirtyClassLookup, + @Nullable BytecodeFixerUpper bytecodeFixerUpper, + MixinClassGenerator classGenerator, + int fabricLVTCompatibility, + AuditTrail auditTrail + ) { + this.refmapHolder = refmapHolder; + this.cleanClassLookup = cleanClassLookup; + this.dirtyClassLookup = dirtyClassLookup; + this.bytecodeFixerUpper = bytecodeFixerUpper; + this.classGenerator = classGenerator; + this.fabricLVTCompatibility = fabricLVTCompatibility; + this.auditTrail = auditTrail; + } public PatchEnvironmentImpl(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility, AuditTrail auditTrail) { - this(refmapHolder, cleanClassLookup, MixinClassLookup.INSTANCE, bytecodeFixerUpper, new MixinClassGeneratorImpl(), new InheritanceHandler(MixinClassLookup.INSTANCE), fabricLVTCompatibility, auditTrail); + this(refmapHolder, cleanClassLookup, MixinClassLookup.INSTANCE, bytecodeFixerUpper, new MixinClassGeneratorImpl(), fabricLVTCompatibility, auditTrail); } - + public PatchEnvironmentImpl(RefmapHolder refmapHolder, ClassLookup cleanClassLookup, ClassLookup dirtyClassLookup, @Nullable BytecodeFixerUpper bytecodeFixerUpper, int fabricLVTCompatibility) { - this(refmapHolder, cleanClassLookup, dirtyClassLookup, bytecodeFixerUpper, new MixinClassGeneratorImpl(), new InheritanceHandler(MixinClassLookup.INSTANCE), fabricLVTCompatibility, new AuditTrailImpl()); + this(refmapHolder, cleanClassLookup, dirtyClassLookup, bytecodeFixerUpper, new MixinClassGeneratorImpl(), fabricLVTCompatibility, new AuditTrailImpl()); + } + + @Override + public RefmapHolder refmapHolder() { + return refmapHolder; + } + + @Override + public ClassLookup cleanClassLookup() { + return cleanClassLookup; + } + + @Override + public ClassLookup dirtyClassLookup() { + return dirtyClassLookup; + } + + @Override + public @Nullable BytecodeFixerUpper bytecodeFixerUpper() { + return bytecodeFixerUpper; + } + + @Override + public MixinClassGenerator classGenerator() { + return classGenerator; + } + + @Override + public InheritanceHandler inheritanceHandler(ClassLookup lookup) { + return this.inheritanceHandlers.computeIfAbsent(lookup, InheritanceHandler::new); + } + + @Override + public int fabricLVTCompatibility() { + return fabricLVTCompatibility; + } + + @Override + public AuditTrail auditTrail() { + return auditTrail; } } diff --git a/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotationConstants.java b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotationConstants.java index 96f833d0..8950be5c 100644 --- a/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotationConstants.java +++ b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotationConstants.java @@ -3,10 +3,8 @@ public class MixinAnnotationConstants { public static final String MIXIN_VALUE = "value"; public static final String MIXIN_TARGETS = "targets"; - + public static final String AT_METHOD = "method"; - public static final String AT_TARGET = "target"; - public static final String AT_VALUE = "value"; public static final String AT_VAL_INVOKE = "INVOKE"; public static final String AT_VAL_INVOKE_ASSIGN = "INVOKE_ASSIGN"; public static final String AT_VAL_RETURN = "RETURN"; @@ -15,10 +13,10 @@ public class MixinAnnotationConstants { public static final String AT_SHIFT = "shift"; public static final String PROPERTY_AT = "at"; - public static final String PROPERTY_CONSTANT = "constant"; public static final String PROPERTY_ORDINAL = "ordinal"; public static final String PROPERTY_SLICE = "slice"; - + public static final String PROPERTY_INDEX = "index"; + public static final String SLICE_FROM = "from"; public static final String SLICE_TO = "to"; } diff --git a/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java index cafb21d6..343b08fe 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java +++ b/core/src/main/java/org/sinytra/adapter/patch/DynamicPatches.java @@ -24,7 +24,7 @@ public class DynamicPatches { public static Multimap methodTransformers(List patches) { return ImmutableMultimap.of( TxPhase.EARLY, new LocalCaptureUpgradeTransformer(), - TxPhase.LOADED, new FieldAccessorTypeTransformer(), // TODO EARLY? + TxPhase.LOADED, new FieldAccessorTypeTransformer(), TxPhase.VALIDATED, new PipelineMethodTransformer(patches, false) ); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java index 687bbac3..44644229 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java +++ b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java @@ -10,6 +10,8 @@ import org.sinytra.adapter.env.ctx.RefMapper; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.config.*; +import org.sinytra.adapter.patch.config.key.ControlKeys; +import org.sinytra.adapter.patch.config.key.SpecialKeys; import org.sinytra.adapter.patch.mixin.MixinType; import org.sinytra.adapter.patch.mixin.MixinTypes; import org.sinytra.adapter.analysis.selector.AnnotationHandle; @@ -37,7 +39,7 @@ public static MixinClassHandle parseMixins(ClassNode classNode, PatchEnvironment return new MixinClassHandle(cls, methods); } - private static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, RefMapper mapper) { + public static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, RefMapper mapper) { if (method.visibleAnnotations == null) return null; for (AnnotationNode annotation : method.visibleAnnotations) { @@ -50,9 +52,9 @@ private static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, PropertyContainerTemplate template = mixinType.getConfigurationTemplate(); MutablePropertyContainer properties = MutablePropertyContainer.parse(handle, template, mapper); - properties.setProperty(Keys.MIXIN_TYPE, annotation.desc); - properties.setProperty(Keys.TARGET_CLASS, cls.getSingle().getInternalName()); - properties.setProperty(Keys.RETURN_TYPE, Type.getReturnType(method.desc)); + properties.setProperty(ControlKeys.MIXIN_TYPE, annotation.desc); + properties.setProperty(ControlKeys.TARGET_CLASS, cls.getSingle().getInternalName()); + properties.setProperty(ControlKeys.RETURN_TYPE, Type.getReturnType(method.desc)); properties.setProperty(SpecialKeys.STATIC, MethodHelper.isStatic(method)); return new MixinMethodHandle(mixinType, method, handle, properties); diff --git a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java index afd860d6..765422ac 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java @@ -5,16 +5,13 @@ import com.mojang.logging.LogUtils; import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.env.MixinContext; import org.sinytra.adapter.env.ann.ClassTarget; -import org.sinytra.adapter.env.ctx.PatchContext; -import org.sinytra.adapter.env.ctx.PatchContextImpl; -import org.sinytra.adapter.env.ctx.PatchEnvironment; -import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.env.ctx.*; import org.sinytra.adapter.env.util.MixinAnnotationConstants; -import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.mixin.MixinFlag; import org.sinytra.adapter.patch.mixin.MixinType; import org.sinytra.adapter.transform.ClassTransformer; import org.sinytra.adapter.transform.MethodTransformer; @@ -24,6 +21,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; @@ -67,13 +65,14 @@ public PatchResult process(ClassNode classNode) { } private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, PatchContext patchContext, MixinParser.MixinMethodHandle mixin) { - MethodQualifier target = mixin.properties().getProperty(Keys.TARGET_METHOD).orElse(null); + MethodQualifier target = mixin.properties().getProperty(MixinKeys.TARGET_METHOD).orElse(null); if (target == null) return PatchResult.PASS; // Prepare context AnnotationHandle atHandle = mixin.methodAnnotation().getNested(MixinAnnotationConstants.PROPERTY_AT).orElse(null); MixinType mixinType = mixin.mixinType(); - MixinContext mixinContext = new MixinContext(patchContext, classTarget, classNode, mixin.methodNode(), mixin.methodAnnotation(), atHandle); + Set flags = mixinType.getFlags(); + MixinContext mixinContext = new MixinContext(patchContext, classTarget, classNode, mixin.methodNode(), mixin.methodAnnotation(), atHandle, flags); String mixinId = mixinContext.getMixinId(); // Build base config diff --git a/core/src/main/java/org/sinytra/adapter/patch/Recipe.java b/core/src/main/java/org/sinytra/adapter/patch/Recipe.java index 37d29c4d..835149d2 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/Recipe.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Recipe.java @@ -1,7 +1,7 @@ package org.sinytra.adapter.patch; import com.google.common.base.Suppliers; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.processor.Processors; diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java index 594ee914..5c3c2d5a 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java @@ -68,8 +68,10 @@ public MutablePropertyContainer copy() { @SuppressWarnings({"rawtypes", "unchecked"}) @Override - public MutablePropertyContainer mergeFrom(PropertyContainer other) { - other.getProperties().forEach((p, v) -> setProperty((PropertyKey) p, v)); + public MutablePropertyContainer mergeFrom(@Nullable PropertyContainer other) { + if (other != null) { + other.getProperties().forEach((p, v) -> setProperty((PropertyKey) p, v)); + } return this; } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationImpl.java b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationImpl.java index 660fd6d6..049bc3d9 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationImpl.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationImpl.java @@ -7,6 +7,8 @@ import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.param.Copiable; import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.patch.config.key.ControlKeys; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.util.MethodQualifier; /** @@ -37,90 +39,90 @@ public MutableConfiguration removeProperty(PropertyKey key) { @Override public MutableConfiguration inheritMixinType() { - return inheritProperty(Keys.MIXIN_TYPE); + return inheritProperty(ControlKeys.MIXIN_TYPE); } @Override public MutableConfiguration inheritTargetClass() { - return inheritProperty(Keys.TARGET_CLASS); + return inheritProperty(ControlKeys.TARGET_CLASS); } @Override public MutableConfiguration inheritTargetMethod() { - return inheritProperty(Keys.TARGET_METHOD); + return inheritProperty(MixinKeys.TARGET_METHOD); } @Override public MutableConfiguration inheritAtData() { - return inheritProperty(Keys.TARGET_AT); + return inheritProperty(MixinKeys.TARGET_AT); } @Override public MutableConfiguration inheritParameters() { - return inheritProperty(Keys.PARAMETERS); + return inheritProperty(ControlKeys.PARAMETERS); } @Override public MutableConfiguration inheritReturnType() { - return inheritProperty(Keys.RETURN_TYPE); + return inheritProperty(ControlKeys.RETURN_TYPE); } @Override public MutableConfiguration inheritShouldDelete() { - return inheritProperty(Keys.DELETE); + return inheritProperty(ControlKeys.DELETE); } @Override public String getMixinType() { - return getPropertyOrNull(Keys.MIXIN_TYPE); + return getPropertyOrNull(ControlKeys.MIXIN_TYPE); } @Override public String getTargetClass() { - return getPropertyOrNull(Keys.TARGET_CLASS); + return getPropertyOrNull(ControlKeys.TARGET_CLASS); } @Override public MethodQualifier getTargetMethod() { - return getPropertyOrNull(Keys.TARGET_METHOD); + return getPropertyOrNull(MixinKeys.TARGET_METHOD); } @Override public AtData getAtData() { - return getPropertyOrNull(Keys.TARGET_AT); + return getPropertyOrNull(MixinKeys.TARGET_AT); } @Override public MethodParameters getParameters() { - return getPropertyOrNull(Keys.PARAMETERS); + return getPropertyOrNull(ControlKeys.PARAMETERS); } @Override public Type getReturnType() { - return getPropertyOrNull(Keys.RETURN_TYPE); + return getPropertyOrNull(ControlKeys.RETURN_TYPE); } @Override public boolean shouldDelete() { - Boolean boxed = getProperty(Keys.DELETE).orElse(null); + Boolean boxed = getProperty(ControlKeys.DELETE).orElse(null); return boxed != null && boxed.booleanValue(); } @Override public boolean isCancellable() { - Boolean boxed = getProperty(Keys.CANCELLABLE).orElse(null); + Boolean boxed = getProperty(MixinKeys.CANCELLABLE).orElse(null); return boxed != null && boxed.booleanValue(); } @Override public MutableConfiguration setTargetClass(String targetClass) { - setProperty(Keys.TARGET_CLASS, targetClass); + setProperty(ControlKeys.TARGET_CLASS, targetClass); return this; } @Override public MutableConfiguration setMixinType(String mixinType) { - setProperty(Keys.MIXIN_TYPE, mixinType); + setProperty(ControlKeys.MIXIN_TYPE, mixinType); return this; } @@ -138,31 +140,31 @@ public MutableConfiguration setTargetMethod(MethodNode methodNode) { @Override public MutableConfiguration setTargetMethod(MethodQualifier targetMethod) { - setProperty(Keys.TARGET_METHOD, targetMethod); + setProperty(MixinKeys.TARGET_METHOD, targetMethod); return this; } @Override public MutableConfiguration setAtData(AtData atData) { - setProperty(Keys.TARGET_AT, atData); + setProperty(MixinKeys.TARGET_AT, atData); return this; } @Override public MutableConfiguration setParameters(MethodParameters parameters) { - setProperty(Keys.PARAMETERS, parameters); + setProperty(ControlKeys.PARAMETERS, parameters); return this; } @Override public MutableConfiguration setReturnType(Type returnType) { - setProperty(Keys.RETURN_TYPE, returnType); + setProperty(ControlKeys.RETURN_TYPE, returnType); return this; } @Override public MutableConfiguration setShouldDelete(boolean delete) { - setProperty(Keys.DELETE, delete); + setProperty(ControlKeys.DELETE, delete); return this; } @@ -216,4 +218,10 @@ public MutableConfiguration copy() { public MutableConfiguration childConfig() { return new ConfigurationImpl(this.template, this); } + + @Override + public MutableConfiguration mergeFrom(@Nullable PropertyContainer other) { + super.mergeFrom(other); + return this; + } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationTemplates.java b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationTemplates.java index 0704c52e..370d7b8e 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationTemplates.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/ConfigurationTemplates.java @@ -1,15 +1,18 @@ package org.sinytra.adapter.patch.config; +import org.sinytra.adapter.patch.config.key.ControlKeys; +import org.sinytra.adapter.patch.config.key.MixinKeys; + public final class ConfigurationTemplates { public static final PropertyContainerTemplate MIXIN_BASE = PropertyContainerTemplate.builder() - .require(Keys.MIXIN_TYPE, Keys.TARGET_CLASS, Keys.TARGET_METHOD, Keys.PARAMETERS, Keys.RETURN_TYPE) - .keys(Keys.LOCALS, Keys.REQUIRE) + .require(ControlKeys.MIXIN_TYPE, ControlKeys.TARGET_CLASS, MixinKeys.TARGET_METHOD, ControlKeys.PARAMETERS, ControlKeys.RETURN_TYPE) + .keys(MixinKeys.LOCALS, MixinKeys.REQUIRE) .build(); public static final PropertyContainerTemplate MIXIN_AT = MIXIN_BASE.extend() - .require(Keys.TARGET_AT) + .require(MixinKeys.TARGET_AT) .build(); public static final PropertyContainerTemplate DELETE = PropertyContainerTemplate.builder() - .require(Keys.DELETE) + .require(ControlKeys.DELETE) .build(); private ConfigurationTemplates() { diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/MutableConfiguration.java b/core/src/main/java/org/sinytra/adapter/patch/config/MutableConfiguration.java index 36966db3..744090ce 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/MutableConfiguration.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/MutableConfiguration.java @@ -58,5 +58,7 @@ default MutableConfiguration setTargetClass(ClassNode targetClass) { MutableConfiguration removeProperty(PropertyKey key); + MutableConfiguration mergeFrom(@Nullable PropertyContainer other); + void inheritProperyIfAbsent(PropertyKey key); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/MutablePropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/MutablePropertyContainer.java index 023ebc07..511ebbca 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/MutablePropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/MutablePropertyContainer.java @@ -26,5 +26,5 @@ static MutablePropertyContainer parse(AnnotationHandle handle, @Nullable Propert MutablePropertyContainer removeProperty(PropertyKey key); - MutablePropertyContainer mergeFrom(PropertyContainer other); + MutablePropertyContainer mergeFrom(@Nullable PropertyContainer other); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java index 25f71f4e..4131e000 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java @@ -32,7 +32,10 @@ public Serializer serializer() { } public Object serialize(T value) { - return this.serializer == null ? value : this.serializer.serialize(value); + if (this.serializer == null) { + throw new RuntimeException("Cannot serialize property '%s' as it does not define a serialized".formatted(this.name)); + } + return this.serializer.serialize(value); } @Override @@ -47,7 +50,10 @@ public static PropertyKey create(String name) { } public static PropertyKey create(String name, Class type) { - return PropertyKey.builder(name).parseAs(type).build(); + return PropertyKey.builder(name) + .parseAs(type) + .serializable() + .build(); } public static Builder builder(String name) { @@ -93,6 +99,11 @@ public Builder parser(Parser parser) { return this; } + public Builder serializable() { + this.serializer = o -> o; + return this; + } + public Builder serializer(Serializer serializer) { this.serializer = serializer; return this; diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/key/ControlKeys.java b/core/src/main/java/org/sinytra/adapter/patch/config/key/ControlKeys.java new file mode 100644 index 00000000..d0969116 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/config/key/ControlKeys.java @@ -0,0 +1,33 @@ +package org.sinytra.adapter.patch.config.key; + +import org.objectweb.asm.Type; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.patch.config.PropertyKey; + +import java.util.List; + +/** + * Mixin Configuration Keys used internally by all mixin types. Never serialized. + */ +@SuppressWarnings("unchecked") +public final class ControlKeys { + // Mixin meta + public static final PropertyKey MIXIN_TYPE = PropertyKey.create("mixin_type"); + public static final PropertyKey TARGET_CLASS = PropertyKey.create("target_class"); + // Method + public static final PropertyKey PARAMETERS = PropertyKey.create("parameters"); + public static final PropertyKey RETURN_TYPE = PropertyKey.create("return_type"); + // Control + public static final PropertyKey DELETE = PropertyKey.create("delete"); + + private ControlKeys() { + } + + @SuppressWarnings("rawtypes") + public static T parseSingle(Object obj, Class cls) { + if (obj instanceof List list) { + return list.size() == 1 ? (T) list.getFirst() : null; + } + return cls.isInstance(obj) ? (T) obj : null; + } +} diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java b/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java similarity index 67% rename from core/src/main/java/org/sinytra/adapter/patch/config/Keys.java rename to core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java index 6b414258..ce1d99a2 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/Keys.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java @@ -1,58 +1,54 @@ -package org.sinytra.adapter.patch.config; +package org.sinytra.adapter.patch.config.key; -import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.ann.ConstantData; import org.sinytra.adapter.env.ann.SliceData; -import org.sinytra.adapter.env.param.MethodParameters; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.config.PropertyKey; import org.sinytra.adapter.util.MethodQualifier; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.util.List; +/** + * Mixin Configuration Keys that directly map to annotation properties + */ @SuppressWarnings("unchecked") -public final class Keys { - // Mixin meta - public static final PropertyKey MIXIN_TYPE = PropertyKey.create("mixin_type"); - public static final PropertyKey TARGET_CLASS = PropertyKey.create("target_class"); +public class MixinKeys { public static final PropertyKey TARGET_METHOD = PropertyKey.builder("method") .parser((value, mapper) -> { // Get method targets - List methodRefs = (List) value; - if (methodRefs.size() != 1) { + String methodRef = ControlKeys.parseSingle(value, String.class); + if (methodRef == null) { // We only support single method targets for now return null; } // Resolve method reference - String reference = mapper.remap(methodRefs.getFirst()); + String reference = mapper.remap(methodRef); // Extract owner, name and desc using regex return MethodQualifier.parse(reference).orElse(null); }) + .serializer(q -> List.of(q.asDescriptor())) .build(); public static final PropertyKey TARGET_AT = PropertyKey.builder("at") .parser((value, mapper) -> { - AnnotationNode node = parseSingle(value, AnnotationNode.class); + AnnotationNode node = ControlKeys.parseSingle(value, AnnotationNode.class); if (node == null) return null; AnnotationHandle handle = new AnnotationHandle(node); return AtData.parse(handle, mapper).orElse(null); }) + .serializer(a -> List.of(a.toAnnotationNode())) .build(); public static final PropertyKey TARGET_CONSTANT = PropertyKey.builder("constant") .parser((value, mapper) -> { - AnnotationNode node = parseSingle(value, AnnotationNode.class); + AnnotationNode node = ControlKeys.parseSingle(value, AnnotationNode.class); AnnotationHandle handle = new AnnotationHandle(node); return ConstantData.parse(handle).orElse(null); }) + .serializer(c -> List.of(c.toAnnotationNode())) .build(); - // Method - public static final PropertyKey PARAMETERS = PropertyKey.create("parameters"); - public static final PropertyKey RETURN_TYPE = PropertyKey.create("return_type"); - // Control - public static final PropertyKey DELETE = PropertyKey.create("delete"); - // Mixin data public static final PropertyKey CANCELLABLE = PropertyKey.create("cancellable", Boolean.class); public static final PropertyKey INDEX = PropertyKey.create("index", Integer.class); @@ -60,24 +56,15 @@ public final class Keys { public static final PropertyKey ARGS_ONLY = PropertyKey.create("argsOnly", Boolean.class); public static final PropertyKey SLICE = PropertyKey.builder("slice") .parser((value, mapper) -> SliceData.parse(new AnnotationHandle((AnnotationNode) value), mapper)) + .serializer(SliceData::toAnnotationNode) .build(); public static final PropertyKey> SLICES = PropertyKey.>builder("slice") .parser((value, mapper) -> ((List) value).stream() .map(AnnotationHandle::new) .map(n -> SliceData.parse(n, mapper)) .toList()) + .serializer(l -> l.stream().map(SliceData::toAnnotationNode).toList()) .build(); public static final PropertyKey LOCALS = PropertyKey.create("locals", LocalCapture.class); public static final PropertyKey REQUIRE = PropertyKey.create("require", Integer.class); - - private Keys() { - } - - @SuppressWarnings("rawtypes") - private static T parseSingle(Object obj, Class cls) { - if (obj instanceof List list) { - return list.size() == 1 ? (T) list.getFirst() : null; - } - return cls.isInstance(obj) ? (T) obj : null; - } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/SpecialKeys.java b/core/src/main/java/org/sinytra/adapter/patch/config/key/SpecialKeys.java similarity index 76% rename from core/src/main/java/org/sinytra/adapter/patch/config/SpecialKeys.java rename to core/src/main/java/org/sinytra/adapter/patch/config/key/SpecialKeys.java index 223ee6fc..0b9d2418 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/SpecialKeys.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/key/SpecialKeys.java @@ -1,10 +1,14 @@ -package org.sinytra.adapter.patch.config; +package org.sinytra.adapter.patch.config.key; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.MethodInsnNode; +import org.sinytra.adapter.patch.config.PropertyKey; import java.util.function.Consumer; +/** + * Mixin-type-specific Configuration Keys. Never serialized. + */ public final class SpecialKeys { // Hidden public static final PropertyKey EXTRACT_TARGET = PropertyKey.create("_extract_target_minsn"); diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java index 26466c61..2b700e24 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java @@ -2,13 +2,15 @@ import org.objectweb.asm.Type; import org.sinytra.adapter.patch.config.ConfigurationTemplates; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameter; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.config.*; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.key.MixinKeys; +import org.sinytra.adapter.patch.config.key.SpecialKeys; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; import org.sinytra.adapter.patch.resolver.injection.ArbitraryInjectionPointSubResolver; @@ -23,7 +25,7 @@ public class InjectMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() - .keys(Keys.SLICES, Keys.CANCELLABLE) + .keys(MixinKeys.SLICES, MixinKeys.CANCELLABLE) .build(); @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinFlag.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinFlag.java new file mode 100644 index 00000000..64a798b5 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinFlag.java @@ -0,0 +1,20 @@ +package org.sinytra.adapter.patch.mixin; + +public enum MixinFlag { + /** + * New injection point must have the same return type + */ + RETURN_TYPE_SENSITIVE, + /** + * Try to keep at target same when moving target methods + */ + AT_TARGET_SENSITIVE, + /** + * The injection target is an indexed variable + */ + TARGETS_VARIABLE, + /** + * The first mixin method param is an instance variable + */ + ACCEPTS_INSTANCE +} diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java index bcd07f90..310cf58b 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.patch.mixin; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; @@ -9,12 +9,19 @@ import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; +import java.util.EnumSet; +import java.util.Set; + /** * Handles configuration and behavior specific to a Mixin type */ public interface MixinType { PropertyContainerTemplate getConfigurationTemplate(); + default Set getFlags() { + return EnumSet.noneOf(MixinFlag.class); + } + TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors); TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java index 5eb7ee03..2b0ac3ed 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java @@ -2,18 +2,15 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.config.ConfigurationTemplates; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.config.*; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameter; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; -import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; -import org.sinytra.adapter.patch.config.MutableConfiguration; -import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; import org.sinytra.adapter.patch.resolver.injection.ArbitraryInjectionPointSubResolver; @@ -24,11 +21,11 @@ import java.util.List; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.SINGLE_ANY; -import static org.sinytra.adapter.patch.config.Keys.INDEX; +import static org.sinytra.adapter.patch.config.key.MixinKeys.INDEX; public class ModifyArgMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() - .keys(Keys.INDEX) + .keys(MixinKeys.INDEX) .build(); @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java index 471c1a86..b202d1e1 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java @@ -1,12 +1,12 @@ package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.config.ConfigurationTemplates; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; import org.sinytra.adapter.patch.processor.Processors; @@ -16,11 +16,13 @@ import org.sinytra.adapter.patch.resolver.special.ResolverSyntheticInstanceof; import org.sinytra.adapter.util.MethodQualifier; +import java.util.EnumSet; import java.util.List; +import java.util.Set; -import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.SINGLE_ANY; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class ModifyExpressionValueMixin implements MixinType { @Override @@ -28,6 +30,11 @@ public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } + @Override + public Set getFlags() { + return EnumSet.of(MixinFlag.RETURN_TYPE_SENSITIVE); + } + @Override public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { resolvers.getOrThrow(InjectionPointResolver.class) diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java index dad9cd58..d8a3d81f 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.patch.mixin; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java index 46a98f51..d7d7d85e 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java @@ -1,17 +1,14 @@ package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.config.ConfigurationTemplates; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.config.*; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameter; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; -import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; -import org.sinytra.adapter.patch.config.MutableConfiguration; -import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; @@ -28,7 +25,7 @@ public class ModifyVariableMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() - .keys(Keys.ARGS_ONLY, Keys.ORDINAL, Keys.INDEX, Keys.SLICE) + .keys(MixinKeys.ARGS_ONLY, MixinKeys.ORDINAL, MixinKeys.INDEX, MixinKeys.SLICE) .build(); @Override @@ -52,9 +49,9 @@ public TxResult preProcess(MixinContext context, MutableConfiguration clean, Res @Override public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - dirty.inheritProperyIfAbsent(Keys.SLICE); + dirty.inheritProperyIfAbsent(MixinKeys.SLICE); - boolean argsOnly = clean.getProperty(Keys.ARGS_ONLY).orElse(false); + boolean argsOnly = clean.getProperty(MixinKeys.ARGS_ONLY).orElse(false); if (argsOnly && dirty.getTargetMethod() != null && !dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { Type cleanVarType = clean.getParameters().getTypes(SINGLE_ANY).getFirst(); List cleanTargetMethodParams = Parameters.getParameterTypes(clean.getTargetMethod().desc()); diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java index 5d23c515..dab5190c 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java @@ -1,27 +1,29 @@ package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.config.ConfigurationTemplates; -import org.sinytra.adapter.env.MixinContext; -import org.sinytra.adapter.env.util.MixinAnnotationConstants; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.env.util.MixinAnnotationConstants; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.processor.ParametersProcessor; import org.sinytra.adapter.patch.processor.Processors; +import org.sinytra.adapter.patch.processor.redirect.DivertRedirectProcessor; import org.sinytra.adapter.patch.processor.redirect.ParameterUsageProcessor; -import org.sinytra.adapter.patch.processor.ParametersProcessor; import org.sinytra.adapter.patch.resolver.Resolvers; import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.resolver.special.ResolverSyntheticInstanceof; -import org.sinytra.adapter.patch.processor.redirect.DivertRedirectProcessor; import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; +import java.util.Set; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.CAPTURED_PARAMS; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; @@ -32,6 +34,11 @@ public PropertyContainerTemplate getConfigurationTemplate() { return ConfigurationTemplates.MIXIN_AT; } + @Override + public Set getFlags() { + return EnumSet.of(MixinFlag.AT_TARGET_SENSITIVE, MixinFlag.ACCEPTS_INSTANCE); + } + @Override public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { resolvers. @@ -57,7 +64,7 @@ public TxResult preProcess(MixinContext context, MutableConfiguration clean, Res .build(); clean.setParameters(params); - + return TxResult.SUCCESS; } diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java index d2cb66dc..090d4bcd 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java @@ -2,17 +2,14 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.config.ConfigurationTemplates; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.patch.config.*; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.MethodHelper; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; -import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; -import org.sinytra.adapter.patch.config.MutableConfiguration; -import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.processor.ParametersProcessor; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.processor.wrapop.WrapOpParamsProcessor; @@ -24,13 +21,15 @@ import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; +import java.util.Set; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.*; public class WrapOperationMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_BASE.extend() - .requireOne(Keys.TARGET_AT, Keys.TARGET_CONSTANT) + .requireOne(MixinKeys.TARGET_AT, MixinKeys.TARGET_CONSTANT) .build(); @Override @@ -38,6 +37,11 @@ public PropertyContainerTemplate getConfigurationTemplate() { return TEMPLATE; } + @Override + public Set getFlags() { + return EnumSet.of(MixinFlag.AT_TARGET_SENSITIVE, MixinFlag.ACCEPTS_INSTANCE); + } + @Override public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { resolvers.getOrThrow(InjectionPointResolver.class) diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java index 2560aede..5587e26f 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.patch.processor; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java deleted file mode 100644 index a1e8f7c8..00000000 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/InjectionTargetProcessor.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.sinytra.adapter.patch.processor; - -import org.sinytra.adapter.env.MixinContext; -import org.sinytra.adapter.env.ann.ConstantData; -import org.sinytra.adapter.env.util.MixinAnnotationConstants; -import org.sinytra.adapter.env.util.MixinAnnotations; -import org.sinytra.adapter.patch.Recipe; -import org.sinytra.adapter.patch.TxResult; -import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; - -public class InjectionTargetProcessor implements Processor { - @Override - public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { - if (!dirty.hasProperty(Keys.TARGET_AT) && !dirty.hasProperty(Keys.TARGET_CONSTANT)) { - return TxResult.PASS; - } - - AnnotationHandle annotation = context.methodAnnotation(); - - annotation.removeValues(MixinAnnotationConstants.PROPERTY_AT); - if (dirty.getAtData() != null) { - AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_AT, MixinAnnotations.AT); - dirty.getAtData().apply(handle); - } - - annotation.removeValues(MixinAnnotationConstants.PROPERTY_CONSTANT); - if (dirty.hasProperty(Keys.TARGET_CONSTANT)) { - AnnotationHandle handle = annotation.getNestedOrAppend(MixinAnnotationConstants.PROPERTY_CONSTANT, MixinAnnotations.CONSTANT); - ConstantData cst = dirty.getProperty(Keys.TARGET_CONSTANT).orElseThrow(); - cst.apply(handle); - } - - // methodContext.recordAudit(this, "Change injection point to %s", this.target); - - return TxResult.SUCCESS; - } -} diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java index 5e29c3f7..07541494 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java @@ -2,7 +2,7 @@ import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java index 91310d5d..2c777b85 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java @@ -3,7 +3,7 @@ import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; import org.objectweb.asm.tree.VarInsnNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java index b26a57cb..093a4dc6 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/Processor.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.patch.processor; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java b/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java index 6e2a1bc2..0db56a5c 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java @@ -10,14 +10,24 @@ public Processors() { } private void registerDefaultProcessors() { + // === Major changes first === + // Handle deleted mixins add(new DisableMixinProcessor()); + // Changed class target add(new ExtractMixinProcessor()); + // Replaced mixin types add(new MixinTypeProcessor()); + + // === Standard changes === + // General annotation props + add(new PropertyProcessor()); + // Target method post processor add(new TargetMethodProcessor()); - add(new InjectionTargetProcessor()); + // Mixin method parameters add(new ParametersProcessor()); + // Mixin method return type add(new ReturnTypeProcessor()); - add(new PropertyProcessor()); + // Static access modifier add(new StaticAccessProcessor()); } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java index face8612..25ad25a9 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java @@ -1,24 +1,43 @@ package org.sinytra.adapter.patch.processor; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyKey; +import org.sinytra.adapter.patch.config.key.MixinKeys; -import static org.sinytra.adapter.patch.config.Keys.ORDINAL; -import static org.sinytra.adapter.patch.config.Keys.SLICE; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; public class PropertyProcessor implements Processor { + private static final Set> ACCEPTED_KEYS = Set.of( + MixinKeys.TARGET_METHOD, MixinKeys.TARGET_AT, MixinKeys.TARGET_CONSTANT, + MixinKeys.ORDINAL, MixinKeys.SLICE, MixinKeys.ARGS_ONLY + ); + + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { - // TODO Auto append all props AnnotationHandle handle = context.methodAnnotation(); - dirty.getProperty(ORDINAL) - .ifPresent(o -> handle.setOrAppendNonNull(ORDINAL.name(), o)); - dirty.getProperty(SLICE) - .ifPresent(s -> handle.setOrAppendNonNull(SLICE.name(), s.toAnnotationNode())); + MutableConfiguration subConfig = MutableConfiguration.create(); + ACCEPTED_KEYS.forEach(k -> dirty.getProperty(k) + .ifPresent(v -> subConfig.setProperty((PropertyKey) k, v))); + + // Apply new props + subConfig.apply(handle); + + // Delete removed props + Set removing = recipe.clean().getProperties().keySet().stream() + .filter(ACCEPTED_KEYS::contains) + .filter(Predicate.not(dirty::hasProperty)) + .map(PropertyKey::name) + .collect(Collectors.toSet()); + handle.removeValues(removing.toArray(String[]::new)); return TxResult.SUCCESS; } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/ReturnTypeProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ReturnTypeProcessor.java index c5e6d86a..5dd9b224 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/ReturnTypeProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ReturnTypeProcessor.java @@ -6,7 +6,7 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java index 129dbdbb..8b7b55c7 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java @@ -6,12 +6,12 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.MethodHelper; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.config.key.SpecialKeys; public class StaticAccessProcessor implements Processor { @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/TargetMethodProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/TargetMethodProcessor.java index 661f49bf..03916435 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/TargetMethodProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/TargetMethodProcessor.java @@ -1,26 +1,21 @@ package org.sinytra.adapter.patch.processor; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.env.ctx.LocalVariable; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.env.ctx.LocalVariable; import org.sinytra.adapter.util.AdapterUtil; import java.util.List; -import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_METHOD; - public class TargetMethodProcessor implements Processor { @Override public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { if (dirty.getTargetMethod() == null) return TxResult.FAIL; - context.methodAnnotation() - .setOrAppendNonNull(AT_METHOD, List.of(dirty.getTargetMethod().asDescriptor())); - upgradeCapturedLocals(context.methodNode(), context, recipe); return TxResult.SUCCESS; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java index 9de1e8eb..36902860 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java @@ -6,14 +6,14 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; -import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.config.key.MixinKeys; +import org.sinytra.adapter.patch.config.key.SpecialKeys; import org.sinytra.adapter.patch.processor.Processor; import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; import org.sinytra.adapter.analysis.locals.LocalVariableLookup; @@ -52,7 +52,7 @@ public static PatchResult apply(String targetClassName, MixinContext context, Re TargetPair cleanTarget = recipe.getCleanTarget(); String owner = Optional.ofNullable(cleanTarget).map(t -> t.classNode().name).orElse(targetClassName); - boolean isInherited = context.environment().inheritanceHandler().isClassInherited(targetClassName, owner); + boolean isInherited = context.environment().inheritanceHandler(context.dirtyLookup()).isClassInherited(targetClassName, owner); Candidates candidates = findCandidates(classNode, methodNode); if (!candidates.canMove(classNode, isInherited)) return PatchResult.PASS; @@ -74,7 +74,7 @@ public static PatchResult apply(String targetClassName, MixinContext context, Re // Take care of captured locals PatchResult result = PatchResult.PASS; - boolean capturesLocals = recipe.clean().hasProperty(Keys.LOCALS); + boolean capturesLocals = recipe.clean().hasProperty(MixinKeys.LOCALS); if (capturesLocals) { result = result.or(recreateLocalVariables(methodNode, context, recipe, generatedTarget)); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java index cf97559d..88ccfc25 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java @@ -6,7 +6,7 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.PatchEnvironment; import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.env.util.MixinAnnotations; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/DivertRedirectProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/DivertRedirectProcessor.java index 5080dadb..7e146c6b 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/DivertRedirectProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/DivertRedirectProcessor.java @@ -3,11 +3,11 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.config.key.SpecialKeys; import org.sinytra.adapter.patch.processor.Processor; import org.sinytra.adapter.util.MethodQualifier; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java index 1a312cd4..20eea9b8 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/redirect/ParameterUsageProcessor.java @@ -9,7 +9,7 @@ import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters.ParamGroup; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java index e723af16..b8a0bf69 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java @@ -4,7 +4,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameter; import org.sinytra.adapter.patch.Recipe; diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpSurgeon.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpSurgeon.java index 44a4dbb8..d639d853 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpSurgeon.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpSurgeon.java @@ -7,7 +7,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; @@ -93,7 +93,7 @@ public static boolean tryUpgrade(MixinContext context, Recipe recipe, List }); Consumer castCheck = subList.getFirst() instanceof TypeInsnNode typeInsn && typeInsn.getOpcode() == Opcodes.CHECKCAST ? list -> { - List originalWOCall = new ArrayList<>(ParamTransformationUtil.findWrapOperationOriginalCallArgs(context.methodNode(), context)); + List originalWOCall = new ArrayList<>(ParamTransformationUtil.findWrapOperationOriginalCallArgs(context.methodNode())); // Include final method call and cast originalWOCall.add(originalWOCall.getLast().getNext()); originalWOCall.add(originalWOCall.getLast().getNext()); @@ -133,7 +133,7 @@ public static Multimap getUsedVars(LocalVariableLookup mix .map(l -> l.index) .toList(); - List originalOpCall = ParamTransformationUtil.findWrapOperationOriginalCallArgs(methodNode, context); + List originalOpCall = ParamTransformationUtil.findWrapOperationOriginalCallArgs(methodNode); Multimap usedVars = HashMultimap.create(); for (AbstractInsnNode insn : methodNode.instructions) { if (insn instanceof VarInsnNode varInsn && !originalOpCall.contains(insn) && paramVars.contains(varInsn.var)) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java index c1d78f94..1dd3f089 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java @@ -1,7 +1,7 @@ package org.sinytra.adapter.patch.resolver; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolver.java index dc595ec0..36b4a174 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/Resolver.java @@ -2,7 +2,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java index 02fb341a..0b70d05a 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/SubResolver.java @@ -1,7 +1,7 @@ package org.sinytra.adapter.patch.resolver; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java index 5693a576..762f95e8 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ArbitraryInjectionPointSubResolver.java @@ -3,17 +3,17 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.InsnComparator; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.env.ann.AtData; -import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.mixin.MixinFlag; import org.sinytra.adapter.patch.resolver.SubResolver; -import org.sinytra.adapter.analysis.InsnComparator; -import org.sinytra.adapter.analysis.InstructionMatcher; -import org.sinytra.adapter.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; @@ -93,8 +93,7 @@ private static AbstractInsnNode findCandidates(InstructionMatcher cleanMatcher, private static MethodInsnNode findReplacementInjectionPoint(AbstractInsnNode lastInsn, UnaryOperator flow, MixinContext context, @Nullable String injectionPointTarget) { // Require matching return types for ModifyExpressionValue mixins - // TODO Eliminate use of matchesDesc - if (context.methodAnnotation().matchesDesc(MixinAnnotations.MODIFY_EXPR_VAL) && injectionPointTarget != null) { + if (context.hasFlag(MixinFlag.RETURN_TYPE_SENSITIVE) && injectionPointTarget != null) { Type desiredReturnType = Type.getReturnType(injectionPointTarget); return (MethodInsnNode) AdapterUtil.iterateInsns(lastInsn, flow, v -> v instanceof MethodInsnNode minsn && Type.getReturnType(minsn.desc).equals(desiredReturnType)); diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/AtVariableAssignStoreSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/AtVariableAssignStoreSubResolver.java index c45f42c0..52f2d1b3 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/AtVariableAssignStoreSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/AtVariableAssignStoreSubResolver.java @@ -2,12 +2,12 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.TargetPair; -import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.mixin.MixinFlag; import org.sinytra.adapter.patch.resolver.SubResolver; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.OpcodeUtil; @@ -66,11 +66,9 @@ public Configuration resolve(MixinContext context, Recipe recipe) { return null; } - if (context.methodAnnotation().matchesDesc(MixinAnnotations.WRAP_OPERATION)) { - // In case the mixin is call-sensitive, we try to keep the orignal injection point if the method was moved - if (!previousMethodCall.owner.equals(dirtyPair.classNode().name)) { - return null; - } + // In case the mixin is call-sensitive, we try to keep the orignal injection point if the method was moved + if (context.hasFlag(MixinFlag.AT_TARGET_SENSITIVE) && !previousMethodCall.owner.equals(dirtyPair.classNode().name)) { + return null; } // All checks have passed, proceed to patch method diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ComparingInjectionPointResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ComparingInjectionPointResolver.java index de43f561..d8bfbc42 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ComparingInjectionPointResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ComparingInjectionPointResolver.java @@ -5,7 +5,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.ann.ConstantData; import org.sinytra.adapter.env.ctx.TargetPair; @@ -15,10 +15,9 @@ import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.env.util.TypeConstants; import org.sinytra.adapter.patch.Recipe; -import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; -import org.sinytra.adapter.patch.config.MutableConfiguration; -import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.config.*; +import org.sinytra.adapter.patch.config.key.MixinKeys; +import org.sinytra.adapter.patch.config.key.SpecialKeys; import org.sinytra.adapter.patch.processor.wrapop.WrapOpSurgeon; import org.sinytra.adapter.patch.resolver.SubResolver; import org.sinytra.adapter.analysis.MethodLabelComparator; @@ -146,8 +145,8 @@ private static Optional handleWrapOperationToInstanceOf(Recipe re Multimap usedVars = WrapOpSurgeon.getUsedVars(mixinLocals, inheritedParams, context); MutableConfiguration config = recipe.dirty().copyClean() - .removeProperty(Keys.TARGET_AT) - .setProperty(Keys.TARGET_CONSTANT, ConstantData.classValue(Type.getObjectType(instanceOfCall.desc))) + .removeProperty(MixinKeys.TARGET_AT) + .setProperty(MixinKeys.TARGET_CONSTANT, ConstantData.classValue(Type.getObjectType(instanceOfCall.desc))) .inheritParameters() .inheritReturnType(); MethodParameters parameters = config.getParameters(); diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InheritedInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InheritedInjectionPointSubResolver.java index 9aca076c..5df77fee 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InheritedInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InheritedInjectionPointSubResolver.java @@ -6,7 +6,7 @@ import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodInsnNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.MethodParameters.ParamGroup; @@ -15,6 +15,7 @@ import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.mixin.MixinFlag; import org.sinytra.adapter.patch.resolver.SubResolver; import org.sinytra.adapter.env.ctx.PatchContext; import org.sinytra.adapter.env.ctx.TargetPair; @@ -25,7 +26,6 @@ import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -// TODO Test public class InheritedInjectionPointSubResolver implements SubResolver { @Nullable @Override @@ -44,12 +44,12 @@ public Configuration resolve(MixinContext context, Recipe recipe) { for (AbstractInsnNode insn : targetPair.methodNode().instructions) { if (insn instanceof MethodInsnNode minsn && minsn.name.equals(atTarget.name()) && minsn.desc.equals(atTarget.desc()) && !minsn.owner.equals(owner) - && (context.environment().inheritanceHandler().isClassInherited(minsn.owner, owner) || isFixedField(minsn, context.patchContext())) + && (context.environment().inheritanceHandler(context.dirtyLookup()).isClassInherited(minsn.owner, owner) || isFixedField(minsn, context.patchContext())) ) { MutableConfiguration config = MutableConfiguration.create(); config.setAtData(at.withTarget(minsn)); - if (context.methodAnnotation().matchesDesc(MixinAnnotations.REDIRECT) && minsn.getOpcode() != Opcodes.INVOKESTATIC) { + if (context.hasFlag(MixinFlag.AT_TARGET_SENSITIVE) && minsn.getOpcode() != Opcodes.INVOKESTATIC) { MethodParameters params = recipe.clean().getParameters().copy(); List callParams = params.get(ParamGroup.METHOD_PARAMS); if (!callParams.isEmpty()) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java index 214fc54e..9134dff3 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java @@ -2,7 +2,7 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AbstractInsnNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.resolver.CompoundResolver; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java index 063cbad8..80d79cfb 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java @@ -6,7 +6,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.util.WeighedDisambiguation; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ModifyVarInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ModifyVarInjectionPointSubResolver.java index f78e3a01..38d9ebba 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ModifyVarInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/ModifyVarInjectionPointSubResolver.java @@ -5,7 +5,7 @@ import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.resolver.SubResolver; @@ -17,7 +17,7 @@ import java.util.List; import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_STORE; -import static org.sinytra.adapter.patch.config.Keys.ORDINAL; +import static org.sinytra.adapter.patch.config.key.MixinKeys.ORDINAL; public class ModifyVarInjectionPointSubResolver implements SubResolver { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java index 61ecbc0e..c4c3e8ff 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java @@ -2,26 +2,27 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; +import com.mojang.datafixers.util.Pair; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.analysis.InsnComparator; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.PatchContext; import org.sinytra.adapter.env.ctx.TargetPair; -import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.key.MixinKeys; +import org.sinytra.adapter.patch.mixin.MixinFlag; import org.sinytra.adapter.patch.resolver.Resolver; -import org.sinytra.adapter.analysis.InsnComparator; -import org.sinytra.adapter.analysis.InstructionMatcher; -import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; -import org.sinytra.adapter.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.GeneratedVariables; import org.sinytra.adapter.util.SingleValueHandle; @@ -83,24 +84,26 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { } }); - if (context.methodAnnotation().matchesDesc(MixinAnnotations.MODIFY_VAR)) { + if (context.hasFlag(MixinFlag.TARGETS_VARIABLE)) { LocalVariableLookup cleanTable = recipe.cleanLocalsTable(); if (cleanTable != null) { // Handle modified ordinals - cleanConfig.getProperty(Keys.ORDINAL) + cleanConfig.getProperty(MixinKeys.ORDINAL) .flatMap(ordinal -> cleanTable.getByTypedOrdinal(returnType, ordinal) .flatMap(lvn -> cleanTable.getTypedOrdinal(lvn).map(o -> new LocalVar(lvn, o, true))) - .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, var -> + .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, pair -> MutableConfiguration.create() - .setProperty(Keys.ORDINAL, var.ordinal()) + .setProperty(MixinKeys.ORDINAL, pair.getFirst().ordinal()) + .mergeFrom(pair.getSecond()) ))) // Handle modified indexes - .or(() -> cleanConfig.getProperty(Keys.INDEX) + .or(() -> cleanConfig.getProperty(MixinKeys.INDEX) .flatMap(i -> Optional.ofNullable(cleanTable.getByIndexOrNull(i)) .flatMap(lvn -> cleanTable.getTypedOrdinal(lvn).map(o -> new LocalVar(lvn, o, false))) - .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, var -> + .map(local -> new HandlerInstance<>(ModifyVariableOffsetHandler.INSTANCE, local, pair -> MutableConfiguration.create() - .setProperty(Keys.INDEX, var.lvn().index) + .setProperty(MixinKeys.INDEX, pair.getFirst().lvn().index) + .mergeFrom(pair.getSecond()) )) )) .ifPresent(handlers::add); @@ -240,11 +243,11 @@ private static List findReturnInsns(MethodNode methodNode) { } } - private static class ModifyVariableOffsetHandler implements UpdateHandler { + private static class ModifyVariableOffsetHandler implements UpdateHandler> { private static final ModifyVariableOffsetHandler INSTANCE = new ModifyVariableOffsetHandler(); @Override - public Optional apply(MixinContext mixinContext, TargetPair cleanTarget, TargetPair dirtyTarget, LocalVar local) { + public Optional> apply(MixinContext mixinContext, TargetPair cleanTarget, TargetPair dirtyTarget, LocalVar local) { MethodNode methodNode = mixinContext.methodNode(); Type[] args = Type.getArgumentTypes(methodNode.desc); @@ -263,6 +266,7 @@ public Optional apply(MixinContext mixinContext, TargetPair cleanTarge } return tryFindUpdatedIndex(targetType, cleanTarget, dirtyTarget, local) + .>map(var -> Pair.of(var, null)) .or(() -> tryFindSyntheticVariableIndex(mixinContext, methodNode, cleanTarget, dirtyTarget, local)); } @@ -294,7 +298,7 @@ public Optional apply(MixinContext mixinContext, TargetPair cleanTarge * INVOKEVIRTUAL net/minecraft/world/entity/player/Player.setHealth (F)V * } */ - private static Optional tryFindSyntheticVariableIndex(MixinContext mixinContext, MethodNode methodNode, TargetPair cleanTarget, TargetPair dirtyTarget, LocalVar local) { + private static Optional> tryFindSyntheticVariableIndex(MixinContext mixinContext, MethodNode methodNode, TargetPair cleanTarget, TargetPair dirtyTarget, LocalVar local) { int ordinal = local.ordinal(); Type variableType = Type.getReturnType(methodNode.desc); LocalVariableLookup cleanTable = new LocalVariableLookup(cleanTarget.methodNode()); @@ -318,14 +322,14 @@ private static Optional tryFindSyntheticVariableIndex(MixinContext mix if (dirtyVars.size() == 1) { int dirtyIndex = dirtyVars.getFirst().get(); if (dirtyIndex != variableIndex) { - // FIXME Cannot use set - mixinContext.methodAnnotation().getValue("argsOnly") - .ifPresent(h -> h.set(false)); - // Find new ordinal by index LocalVariableNode lvn = dirtyTable.getByIndex(dirtyIndex); return dirtyTable.getTypedOrdinal(lvn) - .map(o -> new LocalVar(lvn, o)); + .map(o -> Pair.of( + new LocalVar(lvn, o), + MutableConfiguration.create() + .setProperty(MixinKeys.ARGS_ONLY, false) + )); } } break; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java index f2172764..7f0215a0 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java @@ -5,12 +5,12 @@ import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.VarInsnNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.resolver.Resolver; import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.env.ctx.TargetPair; @@ -112,7 +112,7 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { .setAtData(AtData.create(AT_VAL_INVOKE, dirtyMinsn)) .inheritParameters() .inheritReturnType() - .setProperty(Keys.INDEX, i); + .setProperty(MixinKeys.INDEX, i); // TODO Audit // String qualifier = MethodQualifier.create(dirtyMinsn).asDescriptor(); diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarUpgradeResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarUpgradeResolver.java index eaa43f94..5cd214e7 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarUpgradeResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarUpgradeResolver.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.patch.resolver.special; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.Recipe; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ResolverSyntheticInstanceof.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ResolverSyntheticInstanceof.java index 1990dfc3..3ea9b4ef 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ResolverSyntheticInstanceof.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ResolverSyntheticInstanceof.java @@ -3,7 +3,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; import org.sinytra.adapter.patch.config.Configurations; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.Recipe; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/SliceBoundaryResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/SliceBoundaryResolver.java index 055fa824..6e2a3723 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/SliceBoundaryResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/SliceBoundaryResolver.java @@ -5,7 +5,7 @@ import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.ann.SliceData; import org.sinytra.adapter.patch.Recipe; @@ -25,7 +25,7 @@ import java.util.Optional; import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; -import static org.sinytra.adapter.patch.config.Keys.SLICE; +import static org.sinytra.adapter.patch.config.key.MixinKeys.SLICE; public class SliceBoundaryResolver implements Resolver { @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java index d7a5fbca..89bded2f 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java @@ -7,7 +7,7 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.analysis.method.MethodAnalyzer; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java index c08d7237..62f03662 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java @@ -5,7 +5,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java index 2026c0fd..fa1cbb97 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.patch.resolver.target; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.resolver.CompoundResolver; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java index fc65f2ca..d7267c0e 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java @@ -7,7 +7,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; diff --git a/core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java index 7599b631..0c97b1d9 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/MethodTransformer.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.transform; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.env.ctx.PatchResult; diff --git a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java index 2dc5c4bf..31d376e3 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.ann.SliceData; import org.sinytra.adapter.env.ctx.AuditTrail; @@ -13,7 +13,8 @@ import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.key.ControlKeys; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.mixin.MixinType; import org.sinytra.adapter.patch.mixin.MixinTypes; @@ -104,7 +105,7 @@ private PatchResult execute(MixinContext context, Configuration config) { } // 3. Complete dirty config - if (dirtyConfig.hasProperty(Keys.MIXIN_TYPE)) { + if (dirtyConfig.hasProperty(ControlKeys.MIXIN_TYPE)) { String type = dirtyConfig.getMixinType(); MixinType lateMixinType = MixinTypes.getMixinType(Type.getType(type).getInternalName()); if (lateMixinType != null) { @@ -157,7 +158,7 @@ public boolean hasValidSlice(MixinContext context, Configuration config, @Nullab if (target == null) return false; - SliceData slice = config.getProperty(Keys.SLICE).orElse(null); + SliceData slice = config.getProperty(MixinKeys.SLICE).orElse(null); if (slice == null) return true; AtData from = slice.from(); diff --git a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java index 8457719c..abbaa5f9 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java @@ -1,21 +1,18 @@ package org.sinytra.adapter.transform.cls; import org.objectweb.asm.Type; -import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InnerClassNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.env.ann.ClassTarget; -import org.sinytra.adapter.patch.mixin.MixinTypes; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.transform.ClassTransformer; import org.sinytra.adapter.env.ctx.PatchContext; import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.patch.MixinParser; +import org.sinytra.adapter.patch.config.key.MixinKeys; +import org.sinytra.adapter.transform.ClassTransformer; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; -import java.util.List; - /** * Handle cases where a method targets an anonymous class whose index has changed. */ @@ -52,7 +49,7 @@ public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchCont if (!inner.name.equals(target) && cleanOuterMethod.matches(null, inner.outerMethod, inner.outerMethodDesc)) { classTarget.set(Type.getObjectType(inner.name)); - stripOwnerFromMixinTargets(classNode, context, inner.name); + stripOwnerFromMixinTargets(classNode, classTarget, context, inner.name); return PatchResult.APPLY; } } @@ -61,26 +58,15 @@ public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchCont return PatchResult.PASS; } - // TODO Improve so that we don't need to manually scan the annotations - private static void stripOwnerFromMixinTargets(ClassNode classNode, PatchContext context, String newOwner) { + private static void stripOwnerFromMixinTargets(ClassNode classNode, ClassTarget classTarget, PatchContext context, String newOwner) { for (MethodNode method : classNode.methods) { - if (method.visibleAnnotations != null) { - for (AnnotationNode annotation : method.visibleAnnotations) { - if (MixinTypes.getMixinType(annotation.desc) != null) { - AnnotationHandle handle = new AnnotationHandle(annotation); - handle.>getValue("method").ifPresent(val -> { - List mapped = val.get().stream() - .map(target -> { - String remapped = context.remap(target); - MethodQualifier q = MethodQualifier.parse(remapped).orElse(null); - return q == null ? target : "L" + newOwner + ";" + q.name() + q.desc(); - }) - .toList(); - val.set(mapped); - }); - } - } - } + MixinParser.MixinMethodHandle handle = MixinParser.parseMixin(classTarget, method, context); + if (handle == null) continue; + + handle.properties().getProperty(MixinKeys.TARGET_METHOD) + .map(q -> q.withOwner(newOwner)) + .map(MixinKeys.TARGET_METHOD::serialize) + .ifPresent(q -> handle.methodAnnotation().setOrAppendNonNull(MixinKeys.TARGET_METHOD.name(), q)); } } } diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/InjectParameterTransform.java b/core/src/main/java/org/sinytra/adapter/transform/param/InjectParameterTransform.java index 616d2407..d0efd379 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/InjectParameterTransform.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/InjectParameterTransform.java @@ -4,32 +4,34 @@ import org.objectweb.asm.Type; import org.objectweb.asm.TypeReference; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MethodHelper; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.analysis.locals.LVTSnapshot; import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.patch.mixin.MixinFlag; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.PROPERTY_INDEX; import static org.sinytra.adapter.transform.param.ParamTransformationUtil.calculateLVTIndex; // TODO Cleanup param transformers public record InjectParameterTransform(int index, Type type) implements ParameterTransformer { @Override public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContext context, List parameters, int offset) { - boolean isNonStatic = (methodNode.access & Opcodes.ACC_STATIC) == 0; - final int index = this.index + offset; + boolean isNonStatic = !MethodHelper.isStatic(methodNode); + int index = this.index + offset; if (index >= parameters.size() + 1) { return PatchResult.PASS; } AnnotationHandle annotation = context.methodAnnotation(); - - if (annotation.matchesDesc(MixinAnnotations.MODIFY_VAR)) { - annotation.getValue("index").ifPresent(indexHandle -> { + if (context.hasFlag(MixinFlag.TARGETS_VARIABLE)) { + annotation.getValue(PROPERTY_INDEX).ifPresent(indexHandle -> { int indexValue = indexHandle.get(); if (indexValue >= index) { indexHandle.set(indexValue + 1); @@ -37,14 +39,12 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContex }); return PatchResult.APPLY; } - if (annotation.matchesDesc(MixinAnnotations.MODIFY_ARGS)) { ModifyArgsOffsetUpgrader.upgradeAfterParamInsert(methodNode, this.index); return PatchResult.APPLY; } LocalVariableNode self = methodNode.localVariables.stream().filter(lvn -> lvn.index == 0).findFirst().orElseThrow(); - int lvtIndex = calculateLVTIndex(parameters, isNonStatic, index); LVTSnapshot.with(methodNode, () -> { diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/InlineParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/InlineParameterTransformer.java index 13c91384..f3c9b11a 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/InlineParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/InlineParameterTransformer.java @@ -4,7 +4,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.analysis.locals.LVTSnapshot; import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.util.AdapterUtil; diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/MoveParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/MoveParametersTransformer.java index e396225d..9fd504b0 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/MoveParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/MoveParametersTransformer.java @@ -6,7 +6,7 @@ import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.ParameterNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.analysis.locals.LVTSnapshot; import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.env.ctx.PatchResult; diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/ParamTransformationUtil.java b/core/src/main/java/org/sinytra/adapter/transform/param/ParamTransformationUtil.java index c899579a..12103d37 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/ParamTransformationUtil.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ParamTransformationUtil.java @@ -5,8 +5,6 @@ import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; -import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; @@ -25,33 +23,28 @@ public static int calculateLVTIndex(List parameters, boolean nonStatic, in return lvt; } - public static List findWrapOperationOriginalCall(MethodNode methodNode, MixinContext context) { - if (context.methodAnnotation().matchesDesc(MixinAnnotations.WRAP_OPERATION)) { - List list = new ArrayList<>(); - outer: - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof MethodInsnNode minsn && WO_ORIGINAL_CALL.matches(minsn)) { - for (AbstractInsnNode prev = insn.getPrevious(); prev != null; prev = prev.getPrevious()) { - if (prev instanceof LabelNode) { - continue outer; - } - if (AdapterUtil.canHandleLocalVarInsnValue(prev)) { - list.add(prev); - } + public static List findWrapOperationOriginalCall(MethodNode methodNode) { + List list = new ArrayList<>(); + outer: + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof MethodInsnNode minsn && WO_ORIGINAL_CALL.matches(minsn)) { + for (AbstractInsnNode prev = insn.getPrevious(); prev != null; prev = prev.getPrevious()) { + if (prev instanceof LabelNode) { + continue outer; + } + if (AdapterUtil.canHandleLocalVarInsnValue(prev)) { + list.add(prev); } } } - return List.copyOf(list); } - return List.of(); + return List.copyOf(list); } - public static List findWrapOperationOriginalCallArgs(MethodNode methodNode, MixinContext context) { - if (context.methodAnnotation().matchesDesc(MixinAnnotations.WRAP_OPERATION)) { - for (AbstractInsnNode insn : methodNode.instructions) { - if (insn instanceof MethodInsnNode minsn && WO_ORIGINAL_CALL.matches(minsn)) { - return MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); - } + public static List findWrapOperationOriginalCallArgs(MethodNode methodNode) { + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof MethodInsnNode minsn && WO_ORIGINAL_CALL.matches(minsn)) { + return MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); } } return List.of(); diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/ParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/ParameterTransformer.java index e3769f23..56cc3dac 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/ParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ParameterTransformer.java @@ -3,7 +3,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.PatchResult; import java.util.List; diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/RemoveParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/RemoveParameterTransformer.java index 6b96a881..6b95e5ce 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/RemoveParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/RemoveParameterTransformer.java @@ -4,7 +4,7 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.analysis.locals.LVTSnapshot; import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.util.AdapterUtil; diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java index 67983483..3b1c9cca 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java @@ -4,7 +4,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.analysis.locals.LocalVariableLookup; @@ -44,7 +44,7 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContex localVar.desc = this.type.getDescriptor(); localVar.signature = null; - List ignoreInsns = findWrapOperationOriginalCall(methodNode, context); + List ignoreInsns = findWrapOperationOriginalCall(methodNode); BytecodeFixerUpper bfu = context.environment().bytecodeFixerUpper(); if (this.upgradeUsage && this.type.getSort() == Type.OBJECT && originalType.getSort() == Type.OBJECT) { // Replace variable usages with the new type diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/SubstituteParameterTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/SubstituteParameterTransformer.java index c8286cbe..d44abffe 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/SubstituteParameterTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/SubstituteParameterTransformer.java @@ -4,7 +4,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.analysis.locals.LVTSnapshot; import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.util.AdapterUtil; diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/SwapParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/SwapParametersTransformer.java index 382530df..fc52b66f 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/SwapParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/SwapParametersTransformer.java @@ -3,7 +3,7 @@ import com.mojang.logging.LogUtils; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.SingleValueHandle; diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java b/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java index b57e1fd7..7ab469bc 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java @@ -7,10 +7,9 @@ import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; -import org.sinytra.adapter.env.util.MixinAnnotations; -import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.patch.mixin.MixinFlag; import java.util.ArrayList; import java.util.Arrays; @@ -19,7 +18,6 @@ public record TransformParameters(List transformers, boolean withOffset) { - // TODO public PatchResult apply(MixinContext context) { ClassNode classNode = context.classNode(); MethodNode methodNode = context.methodNode(); @@ -48,9 +46,8 @@ private void updateDescription(MethodNode methodNode, List parameters) { } private int calculateOffset(MixinContext context) { - AnnotationHandle annotation = context.methodAnnotation(); // If it's a redirect, the first local variable (index 1) is the object instance - boolean needsLocalOffset = annotation.matchesDesc(MixinAnnotations.REDIRECT) || annotation.matchesDesc(MixinAnnotations.WRAP_OPERATION); + boolean needsLocalOffset = context.hasFlag(MixinFlag.ACCEPTS_INSTANCE); return !context.isStatic() && this.withOffset && needsLocalOffset ? 1 : 0; } diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatch.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatch.java index 53d137b8..7f4aea90 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatch.java @@ -1,15 +1,19 @@ package org.sinytra.adapter.transform.patch; import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.transform.MethodTransformer; import java.util.List; +import java.util.function.BiConsumer; public interface MethodPatch { ConfigurationMatcher matcher(); Configuration configuration(); + BiConsumer configCompleter(); + List transforms(); static MethodPatchBuilder builder() { diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java index 22031326..3c2a9ebb 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java @@ -33,7 +33,7 @@ public interface MethodPatchBuilder { MethodPatchBuilder modifyInjectionPoint(String value, String target); - MethodPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues); + MethodPatchBuilder replaceInjectionPoint(String value, String target); MethodPatchBuilder modifyParams(UnaryOperator op); diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java index 9c3cb297..688555f2 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java @@ -3,30 +3,34 @@ import org.objectweb.asm.commons.InstructionAdapter; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.config.MutableConfiguration; -import org.sinytra.adapter.patch.config.SpecialKeys; +import org.sinytra.adapter.patch.config.key.SpecialKeys; import org.sinytra.adapter.transform.MethodTransformer; import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.stream.Stream; import static java.util.function.Predicate.isEqual; -import static org.sinytra.adapter.patch.config.Keys.*; +import static org.sinytra.adapter.patch.config.key.ControlKeys.*; public class MethodPatchBuilderImpl implements MethodPatchBuilder { private final ConfigurationMatcher.Builder matcher = ConfigurationMatcher.builder(); private final MutableConfiguration config = MutableConfiguration.create(); + private BiConsumer configCompleter = (a, b) -> {}; private final List transforms = new ArrayList<>(); @Override public MethodPatch build() { ConfigurationMatcher finalMatcher = this.matcher.build(); - return new MethodPatchImpl(finalMatcher, this.config, this.transforms); + return new MethodPatchImpl(finalMatcher, this.config, this.configCompleter, this.transforms); } @Override @@ -45,25 +49,25 @@ public MethodPatchBuilder targetClass(String... targets) { public MethodPatchBuilder targetMethod(String... targets) { Stream.of(targets) .map(t -> MethodQualifier.parse(t).orElseThrow()) - .forEach(t -> this.matcher.match(TARGET_METHOD, t::matches)); + .forEach(t -> this.matcher.match(MixinKeys.TARGET_METHOD, t::matches)); return this; } @Override public MethodPatchBuilder targetInjectionPoint(String target) { - this.matcher.match(TARGET_AT, t -> target.equals(t.getTarget().orElse(null))); + this.matcher.match(MixinKeys.TARGET_AT, t -> target.equals(t.getTarget().orElse(null))); return this; } @Override public MethodPatchBuilder targetInjectionPoint(String value, String target) { - this.matcher.match(TARGET_AT, t -> value.equals(t.getValue()) && target.equals(t.getTarget().orElse(null))); + this.matcher.match(MixinKeys.TARGET_AT, t -> value.equals(t.getValue()) && target.equals(t.getTarget().orElse(null))); return this; } @Override public MethodPatchBuilder targetConstant(double doubleValue) { - this.matcher.match(TARGET_CONSTANT, c -> { + this.matcher.match(MixinKeys.TARGET_CONSTANT, c -> { // TODO OR check at const value Optional opt = c.doubleValue(); return opt.isPresent() && opt.get() == doubleValue; @@ -73,7 +77,7 @@ public MethodPatchBuilder targetConstant(double doubleValue) { @Override public MethodPatchBuilder targetField(String target) { - // TODO + // TODO Field targets return this; } @@ -92,27 +96,33 @@ public MethodPatchBuilder modifyTarget(String method) { @Override public MethodPatchBuilder modifyInjectionPoint(String target) { - // TODO sort out the value placeholder - this.config.setAtData(AtData.create("", target)); + // AtData requires value which must be copied at transform time + this.configCompleter = this.configCompleter.andThen((clean, dirty) -> + dirty.setAtData(clean.getAtData().withTarget(target))); return this; } @Override public MethodPatchBuilder modifyInjectionPoint(String value, String target) { - // TODO How to not reset other values? - this.config.setAtData(AtData.create(value, target)); + // Resolve dynamically to keep old values + this.configCompleter = this.configCompleter.andThen((clean, dirty) -> + dirty.setAtData(clean.getAtData().withValue(value).withTarget(target))); return this; } @Override - public MethodPatchBuilder modifyInjectionPoint(String value, String target, boolean resetValues) { + public MethodPatchBuilder replaceInjectionPoint(String value, String target) { this.config.setAtData(AtData.create(value, target)); return this; } @Override public MethodPatchBuilder modifyParams(UnaryOperator op) { - + this.configCompleter = this.configCompleter.andThen((clean, dirty) -> { + MethodParameters params = clean.getParameters().copy(); + MethodParameters newParams = op.apply(params); + dirty.setParameters(newParams); + }); return this; } diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchImpl.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchImpl.java index ed6ce9fc..7a2e553f 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchImpl.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchImpl.java @@ -1,18 +1,22 @@ package org.sinytra.adapter.transform.patch; import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.transform.MethodTransformer; import java.util.List; +import java.util.function.BiConsumer; public class MethodPatchImpl implements MethodPatch { private final ConfigurationMatcher matcher; private final Configuration config; + private final BiConsumer configCompleter; private final List transforms; - public MethodPatchImpl(ConfigurationMatcher matcher, Configuration config, List transforms) { + public MethodPatchImpl(ConfigurationMatcher matcher, Configuration config, BiConsumer configCompleter, List transforms) { this.matcher = matcher; this.config = config; + this.configCompleter = configCompleter; this.transforms = transforms; } @@ -26,6 +30,11 @@ public Configuration configuration() { return this.config; } + @Override + public BiConsumer configCompleter() { + return this.configCompleter; + } + @Override public List transforms() { return this.transforms; diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java index 389bbcf0..20dbf53f 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchProcessor.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.transform.patch; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java index 95b455a4..f38b302e 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java @@ -1,6 +1,6 @@ package org.sinytra.adapter.transform.patch; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.Configurations; @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.BiConsumer; public class MethodPatchResolver implements Resolver { private final List patches; @@ -31,6 +32,11 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { Configuration patchConfig = patch.configuration(); dirtyConfig.mergeFrom(patchConfig); + + // Add dynamic properties + BiConsumer completer = patch.configCompleter(); + completer.accept(recipe.clean(), dirtyConfig); + postChanges.addAll(patch.transforms()); } } diff --git a/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java index 71d8a7f4..696b5f1f 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java @@ -5,12 +5,12 @@ import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.AuditTrail; import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.patch.config.Keys; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.transform.MethodTransformer; import org.sinytra.adapter.analysis.locals.LocalVarAnalyzer; import org.sinytra.adapter.env.ctx.PatchResult; @@ -29,7 +29,7 @@ public PatchResult apply(MixinContext context, Configuration config) { TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), config.getTargetMethod()); if (dirtyTarget == null) return PatchResult.PASS; - if (!config.hasProperty(Keys.LOCALS)) return PatchResult.PASS; + if (!config.hasProperty(MixinKeys.LOCALS)) return PatchResult.PASS; // Analyze locals MethodNode methodNode = context.methodNode(); diff --git a/core/src/main/java/org/sinytra/adapter/types/FieldAccessorTypeTransformer.java b/core/src/main/java/org/sinytra/adapter/types/FieldAccessorTypeTransformer.java index a3d2339b..32b803b9 100644 --- a/core/src/main/java/org/sinytra/adapter/types/FieldAccessorTypeTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/types/FieldAccessorTypeTransformer.java @@ -6,15 +6,14 @@ import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MethodHelper; +import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.transform.MethodTransformer; -import org.sinytra.adapter.analysis.selector.FieldMatcher; -import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.util.AdapterUtil; -// TODO Clean up maybe public class FieldAccessorTypeTransformer implements MethodTransformer { private static final String PREFIX = "adapter$"; private static final int PRIORITY_MAX = 9999; @@ -30,7 +29,7 @@ public PatchResult apply(MixinContext context, Configuration config) { .orElse(null); if (fieldFqn == null) return PatchResult.PASS; - String fieldName = new FieldMatcher(fieldFqn).getName(); + String fieldName = getFieldName(fieldFqn); Type owner = context.targetTypes().getFirst(); Pair updatedTypes = bfu.getFieldTypeChange(owner.getInternalName(), fieldName); if (updatedTypes != null) { @@ -38,6 +37,7 @@ public PatchResult apply(MixinContext context, Configuration config) { if (typeAdapter != null) { String targetMethod = addRedirectAcceptorField(owner, methodNode, fieldName, typeAdapter, bfu.getGenerator()); + // Change Accessor to Invoker methodNode.visibleAnnotations.remove(context.methodAnnotation().unwrap()); AnnotationVisitor invokerAnn = methodNode.visitAnnotation(MixinAnnotations.INVOKER, true); invokerAnn.visit("value", targetMethod); @@ -55,7 +55,7 @@ private String addRedirectAcceptorField(Type owner, MethodNode methodNode, Strin Type to = adapter.to(); String methodDesc = Type.getMethodDescriptor(to); if (node.methods.stream().noneMatch(m -> m.name.equals(methodName))) { - boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC; + boolean isStatic = MethodHelper.isStatic(methodNode); MethodNode method = (MethodNode) node.visitMethod(Opcodes.ACC_PUBLIC | (isStatic ? Opcodes.ACC_STATIC : 0), methodName, methodDesc, null, null); { AnnotationVisitor annotationVisitor = method.visitAnnotation(MixinAnnotations.UNIQUE, true); @@ -111,4 +111,9 @@ private static int getReturnOpcode(Type type) { default -> throw new UnsupportedOperationException(); }; } + + private static String getFieldName(String desc) { + int descIndex = desc.indexOf(':'); + return descIndex == -1 ? desc : desc.substring(0, descIndex); + } } diff --git a/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java index 1eb236a1..859ea0ea 100644 --- a/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java +++ b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java @@ -11,7 +11,7 @@ import org.objectweb.asm.tree.analysis.SourceValue; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; -import org.sinytra.adapter.env.MixinContext; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.MethodHelper; import org.sinytra.adapter.env.ctx.PatchEnvironment; import org.sinytra.adapter.env.ctx.TargetPair; diff --git a/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java index a4d62858..5e7fa397 100644 --- a/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java +++ b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java @@ -72,4 +72,8 @@ public String asDescriptor() { } return result + this.name + (this.desc != null ? this.desc : ""); } + + public MethodQualifier withOwner(String owner) { + return new MethodQualifier(owner, this.name, this.desc); + } } From 0e4d4813f7d56cbafaed103a81d6b07afe278fde Mon Sep 17 00:00:00 2001 From: Su5eD Date: Fri, 30 Jan 2026 20:17:25 +0100 Subject: [PATCH 13/27] Fix frame analysis failing due to incorrect maxs --- .../java/org/sinytra/adapter/env/ann/AtData.java | 5 ++++- .../sinytra/adapter/patch/config/PropertyKey.java | 2 +- .../sinytra/adapter/patch/config/key/MixinKeys.java | 2 +- .../patch/processor/ParametersProcessor.java | 12 ++++++++---- .../adapter/test/mixin/BoatRendererMixin.java | 13 +++++++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java index c06bc2ee..62881c1d 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java @@ -52,9 +52,11 @@ public void apply(AnnotationHandle handle) { this.properties.apply(handle); } + @SuppressWarnings({"rawtypes", "unchecked"}) public AnnotationNode toAnnotationNode() { AnnotationNode node = new AnnotationNode(MixinAnnotations.AT); - this.properties.getProperties().forEach((key, value) -> node.visit(key.name(), value)); + this.properties.getProperties() + .forEach((key, value) -> node.visit(key.name(), ((PropertyKey) key).serialize(value))); return node; } @@ -150,6 +152,7 @@ public static class Keys { public static final PropertyKey VALUE = PropertyKey.create("value", String.class); public static final PropertyKey TARGET = PropertyKey.builder("target") .parser((value, mapper) -> mapper.remap((String) value)) + .serializable() .build(); public static final PropertyKey ORDINAL = PropertyKey.create("ordinal", Integer.class); public static final PropertyKey SHIFT = PropertyKey.create("shift", At.Shift.class); diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java index 4131e000..88078c56 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyKey.java @@ -51,8 +51,8 @@ public static PropertyKey create(String name) { public static PropertyKey create(String name, Class type) { return PropertyKey.builder(name) - .parseAs(type) .serializable() + .parseAs(type) .build(); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java b/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java index ce1d99a2..43022457 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java @@ -39,7 +39,7 @@ public class MixinKeys { AnnotationHandle handle = new AnnotationHandle(node); return AtData.parse(handle, mapper).orElse(null); }) - .serializer(a -> List.of(a.toAnnotationNode())) + .serializer(a -> List.of(a.toAnnotationNode())) // FIXME Sometimes a list, sometimes not. How to handle? .build(); public static final PropertyKey TARGET_CONSTANT = PropertyKey.builder("constant") .parser((value, mapper) -> { diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java index 2c777b85..5c3b1797 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java @@ -2,16 +2,17 @@ import com.mojang.datafixers.util.Pair; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; -import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; -import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; -import org.sinytra.adapter.env.ctx.PatchResult; import java.util.List; import java.util.Map; @@ -50,7 +51,10 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe Parameters.applyVarMappings(context.methodNode(), oldVarMap); Parameters.applyAnnotations(context.methodNode(), dirtyParams.merge()); - context.methodNode().maxLocals = context.methodNode().localVariables.size(); + // Temporarily set this to a high number for frame analysis to work + // Will be set correctly by ClassWriter after patching + MethodNode methodNode = context.methodNode(); + methodNode.maxLocals = methodNode.maxStack = 999; return TxResult.SUCCESS; } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java index 1ac9ffcd..50d24c19 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/BoatRendererMixin.java @@ -5,12 +5,15 @@ import com.mojang.datafixers.util.Pair; import net.minecraft.client.model.ListModel; import net.minecraft.client.renderer.entity.BoatRenderer; +import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.vehicle.Boat; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import java.util.Map; +import java.util.Objects; @Mixin(BoatRenderer.class) public class BoatRendererMixin { @@ -23,6 +26,11 @@ public class BoatRendererMixin { ) ) private Object getBoatTextureAndModel(Map>> instance, Object type, Operation original, Boat entity) { + //noinspection ConstantConditions + if (entity instanceof Entity terraformEntity && + (Object) this instanceof EntityRenderer terraformRenderer) { + return terraformRenderer.getTextureLocation(terraformEntity); + } return original.call(instance, type); } @@ -34,6 +42,11 @@ private Object getBoatTextureAndModel(Map>> instance, Object type, Operation original, Boat entity) { + //noinspection ConstantConditions + if (entity instanceof Entity terraformEntity && + (Object) this instanceof EntityRenderer terraformRenderer) { + return terraformRenderer.getTextureLocation(terraformEntity); + } return original.call(instance, type); } } From 5340a933e7e28a43b8595b8cd721322c0f101a15 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sat, 31 Jan 2026 00:22:19 +0100 Subject: [PATCH 14/27] Fix plural key application --- .../sinytra/adapter/env/param/Parameters.java | 2 +- .../patch/config/BasePropertyContainer.java | 14 +++++----- .../config/PropertyContainerTemplate.java | 22 +++++++++++++--- .../adapter/patch/config/key/MixinKeys.java | 6 ++--- .../adapter/patch/mixin/InjectMixin.java | 1 + .../adapter/patch/mixin/ModifyArgMixin.java | 1 + .../mixin/ModifyExpressionValueMixin.java | 11 +++++--- .../patch/mixin/ModifyVariableMixin.java | 1 + .../adapter/patch/mixin/RedirectMixin.java | 26 ++++++++++++++++++- .../patch/mixin/WrapOperationMixin.java | 1 + .../patch/processor/PropertyProcessor.java | 2 +- .../test/mixin/MinecraftMixinPatchTest.java | 6 ++++- 12 files changed, 73 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java b/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java index 4a7707fc..7eb37cfa 100644 --- a/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java @@ -44,7 +44,7 @@ private static void parseAnnotations(Parameter.Builder builder, @Nullable List getParameterTypes(String desc) { - return Arrays.asList(Type.getArgumentTypes(desc)); + return new ArrayList<>(Arrays.asList(Type.getArgumentTypes(desc))); } public static Map> gatherVarMappings(MethodNode method, List cleanParameters, List dirtyParameters, Map replacements) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java index 5c3c2d5a..8a8e9cfc 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/BasePropertyContainer.java @@ -2,14 +2,11 @@ import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.env.ctx.RefMapper; import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.env.ctx.RefMapper; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; public class BasePropertyContainer implements MutablePropertyContainer { private final Map, Object> properties = new HashMap<>(); @@ -78,9 +75,14 @@ public MutablePropertyContainer mergeFrom(@Nullable PropertyContainer other) { @SuppressWarnings({"rawtypes", "unchecked"}) @Override public void apply(AnnotationHandle handle) { + Set> pluralKeys = Optional.ofNullable(this.template) + .map(PropertyContainerTemplate::getPluralKeys) + .orElseGet(Set::of); + this.properties.forEach((key, value) -> { Object serialized = ((PropertyKey) key).serialize(value); - handle.setOrAppendNonNull(key.name(), serialized); + Object actual = pluralKeys.contains(key) ? List.of(serialized) : serialized; + handle.setOrAppendNonNull(key.name(), actual); }); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainerTemplate.java b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainerTemplate.java index 2fabd93d..dbc73dc3 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainerTemplate.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/PropertyContainerTemplate.java @@ -11,10 +11,12 @@ public class PropertyContainerTemplate { private final Set> keys; + private final Set> pluralKeys; private final List constraints; - private PropertyContainerTemplate(Set> keys, List constraints) { + private PropertyContainerTemplate(Set> keys, Set> pluralKeys, List constraints) { this.keys = ImmutableSet.copyOf(keys); + this.pluralKeys = ImmutableSet.copyOf(pluralKeys); this.constraints = ImmutableList.copyOf(constraints); } @@ -22,6 +24,10 @@ public Set> getKeys() { return this.keys; } + public Set> getPluralKeys() { + return this.pluralKeys; + } + public boolean validate(PropertyContainer container) { for (Validator constraint : this.constraints) { if (!constraint.validate(container)) { @@ -32,7 +38,7 @@ public boolean validate(PropertyContainer container) { } public Builder extend() { - return new Builder(this.keys, this.constraints); + return new Builder(this.keys, this.pluralKeys, this.constraints); } public static Builder builder() { @@ -41,15 +47,18 @@ public static Builder builder() { public static class Builder { private final Set> keys; + private final Set> pluralKeys; private final List constraints; public Builder() { this.keys = new HashSet<>(); + this.pluralKeys = new HashSet<>(); this.constraints = new ArrayList<>(); } - public Builder(Set> keys, List constraints) { + public Builder(Set> keys, Set> pluralKeys, List constraints) { this.keys = new HashSet<>(keys); + this.pluralKeys = new HashSet<>(pluralKeys); this.constraints = new ArrayList<>(constraints); } @@ -58,6 +67,11 @@ public Builder keys(PropertyKey... keys) { return this; } + public Builder pluralKeys(PropertyKey... keys) { + this.pluralKeys.addAll(List.of(keys)); + return this; + } + public Builder require(PropertyKey... keys) { keys(keys); return addConstraint(c -> Stream.of(keys).allMatch(c::hasProperty)); @@ -76,7 +90,7 @@ public Builder addConstraint(Validator validator) { } public PropertyContainerTemplate build() { - return new PropertyContainerTemplate(this.keys, this.constraints); + return new PropertyContainerTemplate(this.keys, this.pluralKeys, this.constraints); } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java b/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java index 43022457..f4c37deb 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java +++ b/core/src/main/java/org/sinytra/adapter/patch/config/key/MixinKeys.java @@ -29,7 +29,7 @@ public class MixinKeys { // Extract owner, name and desc using regex return MethodQualifier.parse(reference).orElse(null); }) - .serializer(q -> List.of(q.asDescriptor())) + .serializer(MethodQualifier::asDescriptor) .build(); public static final PropertyKey TARGET_AT = PropertyKey.builder("at") .parser((value, mapper) -> { @@ -39,7 +39,7 @@ public class MixinKeys { AnnotationHandle handle = new AnnotationHandle(node); return AtData.parse(handle, mapper).orElse(null); }) - .serializer(a -> List.of(a.toAnnotationNode())) // FIXME Sometimes a list, sometimes not. How to handle? + .serializer(AtData::toAnnotationNode) .build(); public static final PropertyKey TARGET_CONSTANT = PropertyKey.builder("constant") .parser((value, mapper) -> { @@ -47,7 +47,7 @@ public class MixinKeys { AnnotationHandle handle = new AnnotationHandle(node); return ConstantData.parse(handle).orElse(null); }) - .serializer(c -> List.of(c.toAnnotationNode())) + .serializer(ConstantData::toAnnotationNode) .build(); // Mixin data public static final PropertyKey CANCELLABLE = PropertyKey.create("cancellable", Boolean.class); diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java index 2b700e24..63188391 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java @@ -26,6 +26,7 @@ public class InjectMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() .keys(MixinKeys.SLICES, MixinKeys.CANCELLABLE) + .pluralKeys(MixinKeys.TARGET_METHOD, MixinKeys.TARGET_AT) .build(); @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java index 2b0ac3ed..361a8b05 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyArgMixin.java @@ -26,6 +26,7 @@ public class ModifyArgMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() .keys(MixinKeys.INDEX) + .pluralKeys(MixinKeys.TARGET_METHOD) .build(); @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java index b202d1e1..c21ad1ff 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java @@ -9,6 +9,7 @@ import org.sinytra.adapter.patch.config.ConfigurationTemplates; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; import org.sinytra.adapter.patch.resolver.injection.ArbitraryInjectionPointSubResolver; @@ -25,9 +26,13 @@ import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class ModifyExpressionValueMixin implements MixinType { + private final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + .pluralKeys(MixinKeys.TARGET_METHOD, MixinKeys.TARGET_AT) + .build(); + @Override public PropertyContainerTemplate getConfigurationTemplate() { - return ConfigurationTemplates.MIXIN_AT; + return TEMPLATE; } @Override @@ -43,7 +48,7 @@ public TxResult preProcess(MixinContext context, MutableConfiguration clean, Res .addBefore(InjectionPointResolver.class, new ResolverSyntheticInstanceof(true)); clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, CAPTURED_PARAMS))); - + return TxResult.SUCCESS; } @@ -71,7 +76,7 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo dirty.setParameters(params); dirty.setReturnType(modifyingType); - + return TxResult.SUCCESS; } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java index d7d7d85e..6154fd77 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java @@ -26,6 +26,7 @@ public class ModifyVariableMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() .keys(MixinKeys.ARGS_ONLY, MixinKeys.ORDINAL, MixinKeys.INDEX, MixinKeys.SLICE) + .pluralKeys(MixinKeys.TARGET_METHOD) .build(); @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java index dab5190c..6ea9b92c 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java @@ -1,7 +1,9 @@ package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; +import org.sinytra.adapter.env.ctx.MethodHelper; import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.env.util.MixinAnnotationConstants; @@ -11,6 +13,7 @@ import org.sinytra.adapter.patch.config.ConfigurationTemplates; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.processor.ParametersProcessor; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.processor.redirect.DivertRedirectProcessor; @@ -29,9 +32,13 @@ import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; public class RedirectMixin implements MixinType { + private final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + .pluralKeys(MixinKeys.TARGET_METHOD) + .build(); + @Override public PropertyContainerTemplate getConfigurationTemplate() { - return ConfigurationTemplates.MIXIN_AT; + return TEMPLATE; } @Override @@ -54,7 +61,16 @@ public TxResult preProcess(MixinContext context, MutableConfiguration clean, Res if (targetDesc == null) return TxResult.FAIL; + TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), targetDesc); + if (cleanTarget == null) + return TxResult.FAIL; + List callTypes = Parameters.getParameterTypes(targetDesc.desc()); + if (!MethodHelper.isStatic(cleanTarget.methodNode())) { + Type owner = Type.getObjectType(cleanTarget.classNode().name); + callTypes.addFirst(owner); + } + List methodTypes = Parameters.getParameterTypes(context.methodNode().desc); List capturedMethodParams = new ArrayList<>(methodTypes.subList(callTypes.size(), methodTypes.size())); @@ -77,8 +93,16 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo if (targetDesc == null) return TxResult.FAIL; + TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), targetDesc); + if (dirtyTarget == null) + return TxResult.FAIL; + List dirtyCaptured = context.methods().resolveCapturedMethodParams(recipe.clean(), recipe.dirty()); List callTypes = Parameters.getParameterTypes(targetDesc.desc()); + if (!MethodHelper.isStatic(dirtyTarget.methodNode())) { + Type owner = Type.getObjectType(dirtyTarget.classNode().name); + callTypes.addFirst(owner); + } MethodParameters params = MethodParameters.builder() .putTypes(METHOD_PARAMS, callTypes) diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java index 090d4bcd..234a32c8 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/WrapOperationMixin.java @@ -30,6 +30,7 @@ public class WrapOperationMixin implements MixinType { private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_BASE.extend() .requireOne(MixinKeys.TARGET_AT, MixinKeys.TARGET_CONSTANT) + .pluralKeys(MixinKeys.TARGET_METHOD, MixinKeys.TARGET_AT, MixinKeys.TARGET_CONSTANT) .build(); @Override diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java index 25ad25a9..e5a70dfa 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java @@ -24,7 +24,7 @@ public class PropertyProcessor implements Processor { public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { AnnotationHandle handle = context.methodAnnotation(); - MutableConfiguration subConfig = MutableConfiguration.create(); + MutableConfiguration subConfig = dirty.copyClean(); ACCEPTED_KEYS.forEach(k -> dirty.getProperty(k) .ifPresent(v -> subConfig.setProperty((PropertyKey) k, v))); 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 61daf389..836b018c 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 @@ -214,7 +214,11 @@ protected AssertCallback assertType() { } protected AssertCallback assertTargetMethod() { - Function> targetMethodExtractor = node -> new AnnotationHandle(node).>getValue("method").map(AnnotationValueHandle::get).orElseThrow(); + Function> targetMethodExtractor = node -> + new AnnotationHandle(node). + >getValue("method") + .map(AnnotationValueHandle::get) + .orElseThrow(); return (patched, expected, env) -> { AnnotationNode patchedMethodAnn = patched.visibleAnnotations.getFirst(); From f01372dfe15a3e78bb2b0cd49a2dc98eb22c002f Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sat, 31 Jan 2026 09:28:06 +0100 Subject: [PATCH 15/27] Injection point resolver for modified params --- .../patch/resolver/injection/InjectionPointSubResolvers.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java index 80d79cfb..5e7ff974 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java @@ -26,8 +26,6 @@ public class InjectionPointSubResolvers { public static final SubResolver REPLACED_TYPE = (MixinContext context, Recipe recipe) -> { - if (!recipe.clean().getAtData().getValue().equals(AT_VAL_INVOKE)) return null; - TargetPair cleanPair = recipe.getCleanTarget(); TargetPair dirtyTarget = recipe.getDirtyTarget(); // Find single clean target minsn From 2cdb897b4ce1b4f8afdfcd49ff94f7e134df9724 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sat, 31 Jan 2026 11:09:53 +0100 Subject: [PATCH 16/27] Handle overloaded injection point targets --- .../analysis/method/MethodCallAnalyzer.java | 8 +++ .../sinytra/adapter/env/ann/ClassTarget.java | 6 +- .../sinytra/adapter/env/ctx/MethodHelper.java | 2 +- .../sinytra/adapter/env/ctx/MixinContext.java | 9 ++- .../sinytra/adapter/patch/MixinParser.java | 6 +- .../org/sinytra/adapter/patch/Patcher.java | 2 +- .../adapter/patch/mixin/MixinType.java | 4 ++ .../patch/mixin/ModifyVariableMixin.java | 35 ++++++++- .../patch/processor/PropertyProcessor.java | 2 +- .../injection/InjectionPointResolver.java | 1 + .../injection/InjectionPointSubResolvers.java | 12 ++-- .../OverloadedInjectionPointSubResolver.java | 72 +++++++++++++++++++ .../target/TargetMethodSubResolvers.java | 7 +- .../transform/PipelineMethodTransformer.java | 8 ++- .../cls/DynamicAnonClassIndexPatch.java | 2 + .../DynamicAnonymousShadowFieldTypePatch.java | 2 + .../param/ReplaceParametersTransformer.java | 22 ++++-- .../org/sinytra/adapter/util/AdapterUtil.java | 5 ++ .../sinytra/adapter/util/MethodQualifier.java | 4 ++ .../test/mixin/DynamicMixinPatchTest.java | 11 +++ .../test/mixin/MinecraftMixinPatchTest.java | 11 +++ .../test/mixin/pipeline/GuiGraphicsMixin.java | 37 ++++++++++ 22 files changed, 236 insertions(+), 32 deletions(-) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java create mode 100644 test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiGraphicsMixin.java diff --git a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java index 681fa9cd..a3388a04 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java @@ -16,8 +16,16 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.StreamSupport; public class MethodCallAnalyzer { + public static List getMethodCallMinsns(MethodNode methodNode, MethodQualifier qualifier) { + return StreamSupport.stream(methodNode.instructions.spliterator(), false) + .filter(i -> i instanceof MethodInsnNode minsn && qualifier.matches(minsn)) + .map(MethodInsnNode.class::cast) + .toList(); + } + @Nullable public static List getMethodCallInsns(MethodNode methodNode, MethodInsnNode minsn) { return Optional.ofNullable(getMethodCallSrcInsns(methodNode, minsn)) diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java index 47b8cc3d..d44a6e9f 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java @@ -41,16 +41,14 @@ public List getTypes() { ); } + @Nullable public Type getSingle() { List types = this.either.map(AnnotationValueHandle::get, h -> h.get() .stream() .map(Type::getObjectType) .toList() ); - if (types.size() != 1) { - throw new IllegalStateException("Expected exactly one type, got " + types.size()); - } - return types.getFirst(); + return types.size() != 1 ? null : types.getFirst(); } public void set(Type type) { diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java index ddaa3a76..947fa723 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MethodHelper.java @@ -44,7 +44,7 @@ public class MethodHelper { public MethodHelper(MixinContext context, List targetTypes) { this.context = context; - String singleTargetClass = targetTypes.size() == 1 ? targetTypes.getFirst().getInternalName() : null; + String singleTargetClass = targetTypes.getFirst().getInternalName(); this.methodFinder = new MethodFinder(context.environment(), singleTargetClass); } diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java index 2ccc84ae..79cc74df 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java @@ -7,6 +7,7 @@ import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.env.ann.ClassTarget; import org.sinytra.adapter.patch.mixin.MixinFlag; +import org.sinytra.adapter.patch.mixin.MixinType; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; import org.sinytra.adapter.types.TypeAdapter; @@ -17,6 +18,7 @@ import java.util.Set; public class MixinContext implements RefMapper, Auditor { + private final MixinType mixinType; private final PatchContext patchContext; private final ClassTarget classTarget; private final ClassNode classNode; @@ -32,7 +34,8 @@ public class MixinContext implements RefMapper, Auditor { private final Resolvers resolvers = new Resolvers(); private final Processors processors = new Processors(); - public MixinContext(PatchContext patchContext, ClassTarget classTarget, ClassNode classNode, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation, Set flags) { + public MixinContext(MixinType mixinType, PatchContext patchContext, ClassTarget classTarget, ClassNode classNode, MethodNode methodNode, AnnotationHandle methodAnnotation, AnnotationHandle injectionPointAnnotation, Set flags) { + this.mixinType = mixinType; this.patchContext = patchContext; this.classTarget = classTarget; this.classNode = classNode; @@ -47,6 +50,10 @@ public MixinContext(PatchContext patchContext, ClassTarget classTarget, ClassNod this.mixinId = classNode.name + "#" + methodNode.name + methodNode.desc; } + public MixinType getMixinType() { + return this.mixinType; + } + public boolean hasFlag(MixinFlag flag) { return this.flags.contains(flag); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java index 44644229..2e6c1c37 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java +++ b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java @@ -19,13 +19,14 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class MixinParser { @Nullable public static MixinClassHandle parseMixins(ClassNode classNode, PatchEnvironment environment) { ClassTarget cls = parseTargetClass(classNode); - if (cls == null || cls.getTypes().size() > 1) return null; + if (cls == null) return null; RefMapper refMapper = ref -> environment.refmapHolder().remap(classNode.name, ref); List methods = new ArrayList<>(); @@ -53,7 +54,8 @@ public static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, R MutablePropertyContainer properties = MutablePropertyContainer.parse(handle, template, mapper); properties.setProperty(ControlKeys.MIXIN_TYPE, annotation.desc); - properties.setProperty(ControlKeys.TARGET_CLASS, cls.getSingle().getInternalName()); + String targetClass = Objects.requireNonNullElseGet(cls.getSingle(), () -> cls.getTypes().getFirst()).getInternalName(); + properties.setProperty(ControlKeys.TARGET_CLASS, targetClass); properties.setProperty(ControlKeys.RETURN_TYPE, Type.getReturnType(method.desc)); properties.setProperty(SpecialKeys.STATIC, MethodHelper.isStatic(method)); diff --git a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java index 765422ac..48a7880e 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java @@ -72,7 +72,7 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P AnnotationHandle atHandle = mixin.methodAnnotation().getNested(MixinAnnotationConstants.PROPERTY_AT).orElse(null); MixinType mixinType = mixin.mixinType(); Set flags = mixinType.getFlags(); - MixinContext mixinContext = new MixinContext(patchContext, classTarget, classNode, mixin.methodNode(), mixin.methodAnnotation(), atHandle, flags); + MixinContext mixinContext = new MixinContext(mixinType, patchContext, classTarget, classNode, mixin.methodNode(), mixin.methodAnnotation(), atHandle, flags); String mixinId = mixinContext.getMixinId(); // Build base config diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java index 310cf58b..cd71d1b6 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinType.java @@ -22,6 +22,10 @@ default Set getFlags() { return EnumSet.noneOf(MixinFlag.class); } + default boolean canInject(MixinContext context, Configuration config) { + return true; + } + TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors); TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe); diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java index 6154fd77..1b074582 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyVariableMixin.java @@ -1,13 +1,19 @@ package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; -import org.sinytra.adapter.patch.config.*; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameter; import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.config.PropertyContainerTemplate; import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; @@ -18,7 +24,9 @@ import org.sinytra.adapter.patch.resolver.special.ModifyVarUpgradeResolver; import org.sinytra.adapter.types.TypeAdapter; +import java.util.EnumSet; import java.util.List; +import java.util.Set; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.LOCALS; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.SINGLE_ANY; @@ -34,6 +42,11 @@ public PropertyContainerTemplate getConfigurationTemplate() { return TEMPLATE; } + @Override + public Set getFlags() { + return EnumSet.of(MixinFlag.TARGETS_VARIABLE); + } + @Override public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { resolvers @@ -77,4 +90,24 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo return TxResult.SUCCESS; } + + @Override + public boolean canInject(MixinContext context, Configuration config) { + // Ensure variable at index has the correct type + if (config.hasProperty(MixinKeys.INDEX)) { + MethodNode target = context.methods().findOwnMethod(context.dirtyLookup(), config.getTargetMethod()); + if (target == null) return false; + + Integer index = config.getProperty(MixinKeys.INDEX).orElseThrow(); + LocalVariableLookup lookup = new LocalVariableLookup(target); + + LocalVariableNode node = lookup.getByIndexOrNull(index); + if (node == null) return false; + + Type expectedType = config.getReturnType(); + Type actualType = Type.getType(node.desc); + return expectedType.equals(actualType); + } + return true; + } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java index e5a70dfa..f1cf63c7 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java @@ -16,7 +16,7 @@ public class PropertyProcessor implements Processor { private static final Set> ACCEPTED_KEYS = Set.of( MixinKeys.TARGET_METHOD, MixinKeys.TARGET_AT, MixinKeys.TARGET_CONSTANT, - MixinKeys.ORDINAL, MixinKeys.SLICE, MixinKeys.ARGS_ONLY + MixinKeys.ORDINAL, MixinKeys.INDEX, MixinKeys.SLICE, MixinKeys.ARGS_ONLY ); @SuppressWarnings({"unchecked", "rawtypes"}) diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java index 9134dff3..2ca00811 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointResolver.java @@ -13,6 +13,7 @@ public class InjectionPointResolver extends CompoundResolver { public InjectionPointResolver() { + addSubResolver(new OverloadedInjectionPointSubResolver()); addSubResolver(new InheritedInjectionPointSubResolver()); addSubResolver(InjectionPointSubResolvers.REPLACED_TYPE); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java index 5e7ff974..d14c819f 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/InjectionPointSubResolvers.java @@ -6,24 +6,22 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.analysis.InstructionMatcher; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.analysis.method.MethodInsnMatcher; import org.sinytra.adapter.env.ctx.MixinContext; -import org.sinytra.adapter.env.util.WeighedDisambiguation; +import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.env.util.WeighedDisambiguation; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.resolver.SubResolver; -import org.sinytra.adapter.analysis.InstructionMatcher; -import org.sinytra.adapter.analysis.method.MethodAnalyzer; -import org.sinytra.adapter.analysis.method.MethodInsnMatcher; -import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.util.MethodQualifier; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; - public class InjectionPointSubResolvers { public static final SubResolver REPLACED_TYPE = (MixinContext context, Recipe recipe) -> { TargetPair cleanPair = recipe.getCleanTarget(); diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java new file mode 100644 index 00000000..19ec6cb7 --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java @@ -0,0 +1,72 @@ +package org.sinytra.adapter.patch.resolver.injection; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.util.MixinAnnotationConstants; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.MutableConfiguration; +import org.sinytra.adapter.patch.resolver.SubResolver; +import org.sinytra.adapter.util.AdapterUtil; +import org.sinytra.adapter.util.MethodQualifier; + +import java.util.List; + +public class OverloadedInjectionPointSubResolver implements SubResolver { + @Nullable + @Override + public Configuration resolve(MixinContext context, Recipe recipe) { + TargetPair cleanPair = recipe.getCleanTarget(); + if (cleanPair == null) return null; + + TargetPair dirtyPair = recipe.getDirtyTarget(); + if (dirtyPair == null) return null; + + // Temporarily modify @At data to target INVOKE if originally using INVOKE_ASSIGN + AtData tempAt = getInvokeAtData(recipe.clean().getAtData()); + AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanPair, tempAt); + if (!(cleanInsn instanceof MethodInsnNode cleanMinsn)) return null; + MethodQualifier cleanQualifier = MethodQualifier.create(cleanMinsn); + + TargetPair cleanTarget = context.methods().findMethodPair(context.cleanLookup(), cleanQualifier); + if (cleanTarget == null) return null; + + TargetPair newCleanTarget = context.methods().findMethodPair(context.dirtyLookup(), cleanQualifier); + if (newCleanTarget == null) return null; + + // Check if called clean method was marked as deprecated + if (AdapterUtil.isDeprecated(cleanTarget.methodNode()) || !AdapterUtil.isDeprecated(newCleanTarget.methodNode())) { + return null; + } + + // Check that the deprecated method is not called anymore + List cleanCallsInDirty = MethodCallAnalyzer.getMethodCallMinsns(dirtyPair.methodNode(), cleanQualifier); + if (!cleanCallsInDirty.isEmpty()) return null; + + // Find method calls to potential replacement method + MethodQualifier qualifier = cleanQualifier.ignoreDesc(); + List dirtyCalls = MethodCallAnalyzer.getMethodCallMinsns(dirtyPair.methodNode(), qualifier); + if (dirtyCalls.isEmpty()) return null; + + // All calls target the same overloaded method + boolean allEqual = dirtyCalls.stream().map(m -> m.desc).distinct().limit(2).count() <= 1; + if (allEqual) { + return MutableConfiguration.create() + .setAtData(recipe.clean().getAtData().withTarget(dirtyCalls.getFirst())); + } + + return null; + } + + private AtData getInvokeAtData(AtData at) { + if (at.getValue().equals(MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN)) { + return at.withValue(MixinAnnotationConstants.AT_VAL_INVOKE); + } + return at; + } +} diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java index d7267c0e..ab425e26 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java @@ -8,13 +8,13 @@ import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.resolver.Resolver; import org.sinytra.adapter.patch.resolver.SubResolver; import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; -import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; @@ -22,8 +22,6 @@ import java.util.List; public class TargetMethodSubResolvers { - private static final String DEPRECATED = "Ljava/lang/Deprecated;"; - /** * Handle cases where the target method's parameters have changed *

@@ -114,7 +112,6 @@ private static Configuration resolveReplacementCandidate(MixinContext context, R public static boolean isDirtyDeprecatedMethod(MixinContext context, MethodNode dirty) { TargetPair pair = context.methods().findOwnMethodPair(context.cleanLookup(), MethodQualifier.create(dirty)); - return (pair == null || !AdapterUtil.hasAnnotation(pair.methodNode().visibleAnnotations, DEPRECATED)) - && !AdapterUtil.hasAnnotation(dirty.visibleAnnotations, DEPRECATED); + return (pair == null || !AdapterUtil.isDeprecated(pair.methodNode())) && !AdapterUtil.isDeprecated(dirty); } } diff --git a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java index 31d376e3..223b5b5e 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java @@ -50,7 +50,7 @@ public PatchResult apply(MixinContext context, Configuration config) { if (cleanTarget == null) return PatchResult.PASS; TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), config.getTargetMethod()); - if (!failsDirtyInjectionCheck(context, dirtyTarget) && hasValidSlice(context, config, dirtyTarget)) + if (!failsDirtyInjectionCheck(context, config, dirtyTarget) && hasValidSlice(context, config, dirtyTarget)) return PatchResult.PASS; LOGGER.debug(MIXINPATCH, "Considering method {}", context.getMixinId()); @@ -139,8 +139,10 @@ private PatchResult execute(MixinContext context, Configuration config) { return PatchResult.APPLY; } - public boolean failsDirtyInjectionCheck(MixinContext context, TargetPair dirtyTarget) { - return dirtyTarget == null || !context.methods().hasInjectionTargetInsns(dirtyTarget) + public boolean failsDirtyInjectionCheck(MixinContext context, Configuration config, TargetPair dirtyTarget) { + return !context.getMixinType().canInject(context, config) + || dirtyTarget == null + || !context.methods().hasInjectionTargetInsns(dirtyTarget) && computeConstantTargetInsns(context, dirtyTarget).isEmpty(); } diff --git a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java index abbaa5f9..43706bde 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java @@ -20,6 +20,8 @@ public class DynamicAnonClassIndexPatch implements ClassTransformer { @Override public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context) { Type singleTarget = classTarget.getSingle(); + if (singleTarget == null) return PatchResult.PASS; + String target = singleTarget.getInternalName(); if (!AdapterUtil.isAnonymousClass(target)) { return PatchResult.PASS; diff --git a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonymousShadowFieldTypePatch.java b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonymousShadowFieldTypePatch.java index 0aea7cac..10a57712 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonymousShadowFieldTypePatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonymousShadowFieldTypePatch.java @@ -19,6 +19,8 @@ public class DynamicAnonymousShadowFieldTypePatch implements ClassTransformer { @Override public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context) { Type singleTarget = classTarget.getSingle(); + if (singleTarget == null) return PatchResult.PASS; + String target = singleTarget.getInternalName(); if (!AdapterUtil.isAnonymousClass(target)) { return PatchResult.PASS; diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java index 3b1c9cca..73afb513 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java @@ -74,12 +74,22 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContex } } - if (insn instanceof MethodInsnNode minsn && minsn.owner.equals(originalType.getInternalName())) { - List insns = MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); - // Find var load instruction - for (AbstractInsnNode callInsn : insns) { - if (callInsn instanceof VarInsnNode varinsn && varinsn.var == localVar.index) { - minsn.owner = this.type.getInternalName(); + if (insn instanceof MethodInsnNode minsn) { + // Add casts to usage in method calls + List callArgs = MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); + for (AbstractInsnNode arg : callArgs) { + if (arg instanceof VarInsnNode varInsn && varInsn.var == localVar.index) { + methodNode.instructions.insert(varInsn, new TypeInsnNode(Opcodes.CHECKCAST, originalType.getInternalName())); + } + } + + if (minsn.owner.equals(originalType.getInternalName())) { + List insns = MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); + // Find var load instruction + for (AbstractInsnNode callInsn : insns) { + if (callInsn instanceof VarInsnNode varInsn && varInsn.var == localVar.index) { + minsn.owner = this.type.getInternalName(); + } } } } diff --git a/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java index 859ea0ea..447a6adc 100644 --- a/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java +++ b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java @@ -38,8 +38,13 @@ public final class AdapterUtil { public static final String LAMBDA_PREFIX = "lambda$"; public static final Marker MIXINPATCH = MarkerFactory.getMarker("MIXINPATCH"); private static final Pattern FIELD_REF_PATTERN = Pattern.compile("^(?L.+?;)?(?[^:]+)?:(?.+)?$"); + private static final String DEPRECATED = "Ljava/lang/Deprecated;"; private static final Logger LOGGER = LogUtils.getLogger(); + public static boolean isDeprecated(MethodNode methodNode) { + return hasAnnotation(methodNode.visibleAnnotations, DEPRECATED); + } + public static MethodNode copyMethod(MethodNode original) { MethodNode copy = new MethodNode(original.access, original.name, original.desc, original.signature, original.exceptions.toArray(String[]::new)); original.accept(copy); diff --git a/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java index 5e7fa397..911c6aa6 100644 --- a/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java +++ b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java @@ -76,4 +76,8 @@ public String asDescriptor() { public MethodQualifier withOwner(String owner) { return new MethodQualifier(owner, this.name, this.desc); } + + public MethodQualifier ignoreDesc() { + return new MethodQualifier(this.owner, this.name, null); + } } 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 77c61041..4dee5305 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 @@ -425,6 +425,17 @@ void testSyntheticInstanceofMEV() throws Exception { ); } + @Test + void testModifiedVariableIndex() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mixin/pipeline/GuiGraphicsMixin", + "modifyRenderX", + assertTargetMethod(), + assertInjectionPoint(), + assertIndex() + ); + } + @Override protected LoadResult load(String className, List allowedMethods) throws Exception { 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 836b018c..856e3c6a 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 @@ -271,6 +271,17 @@ protected AssertCallback assertSliceRange() { }; } + protected AssertCallback assertIndex() { + return (patched, expected, env) -> { + AnnotationHandle patchedMethodAnn = new AnnotationHandle(patched.visibleAnnotations.getFirst()); + AnnotationHandle expectedMethodAnn = new AnnotationHandle(expected.visibleAnnotations.getFirst()); + + Assertions.assertThat(patchedMethodAnn.getValue("index").get().get()) + .as("Index") + .isEqualTo(expectedMethodAnn.getValue("index").get().get()); + }; + } + protected AssertCallback assertTargetsConstant() { return (patched, expected, env) -> { AnnotationHandle patchedMethodAnn = new AnnotationHandle(patched.visibleAnnotations.getFirst()); diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiGraphicsMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiGraphicsMixin.java new file mode 100644 index 00000000..53cea86f --- /dev/null +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiGraphicsMixin.java @@ -0,0 +1,37 @@ +package org.sinytra.adapter.test.mixin.pipeline; + +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.List; + +@Mixin(GuiGraphics.class) +public class GuiGraphicsMixin { + @ModifyVariable( + method = "renderTooltipInternal(Lnet/minecraft/client/gui/Font;Ljava/util/List;IILnet/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipPositioner;)V", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V" + ), + index = 11 + ) + public int modifyRenderX(int value, Font textRenderer, List components, int x) { + return value; + } + + @ModifyVariable( + method = "renderTooltipInternal(Lnet/minecraft/client/gui/Font;Ljava/util/List;IILnet/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipPositioner;)V", + at = @At( + value = "INVOKE", + target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V" + ), + index = 12 + ) + public int modifyRenderXExpected(int value, Font textRenderer, List components, int x) { + return value; + } +} From 0c585420d62c28d553c6c243037847c0bb716a58 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sat, 31 Jan 2026 14:47:09 +0100 Subject: [PATCH 17/27] Cast replaced inherited parameters to expected type --- .../org/sinytra/adapter/env/ann/AtData.java | 8 ++ .../adapter/env/util/MixinAnnotations.java | 1 + .../adapter/patch/mixin/MixinTypes.java | 4 +- .../mixin/ModifyExpressionValueMixin.java | 2 +- .../patch/mixin/ModifyReturnValueMixin.java | 48 ++++++++++- .../adapter/patch/mixin/RedirectMixin.java | 2 +- .../processor/ParametersPostProcessor.java | 82 +++++++++++++++++++ .../adapter/patch/processor/Processors.java | 2 + .../special/InjectorOrdinalResolver.java | 52 ++++++++++++ .../transform/PipelineMethodTransformer.java | 8 +- .../param/ReplaceParametersTransformer.java | 28 ++----- .../transform/patch/MethodPatchBuilder.java | 3 +- .../patch/MethodPatchBuilderImpl.java | 8 +- .../transform/patch/MethodPatchResolver.java | 15 +++- .../test/mixin/DynamicMixinPatchTest.java | 10 +++ .../test/mixin/MinecraftMixinPatchTest.java | 13 ++- .../test/mixin/MilkBucketItemMixin.java | 17 +++- .../test/mixin/NaturalSpawnerMixin.java | 19 ++++- .../pipeline/ItemInHandRendererMixin.java | 3 +- .../test/mixin/pipeline/MaceItemMixin.java | 35 ++++++++ 20 files changed, 311 insertions(+), 49 deletions(-) create mode 100644 core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java create mode 100644 test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/MaceItemMixin.java diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java index 62881c1d..377c6615 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/AtData.java @@ -1,5 +1,6 @@ package org.sinytra.adapter.env.ann; +import com.google.common.base.MoreObjects; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.MethodInsnNode; @@ -98,6 +99,13 @@ public int hashCode() { return Objects.hash(properties); } + @Override + public String toString() { + MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this); + this.properties.getProperties().forEach((k, v) -> helper.add(k.name(), v)); + return helper.toString(); + } + public static Optional parse(AnnotationHandle annotation, RefMapper mapper) { PropertyContainer container = MutablePropertyContainer.parseValid(annotation, TEMPLATE, mapper); return Optional.ofNullable(container).map(AtData::new); diff --git a/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotations.java b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotations.java index 2b25ddd2..0f101219 100644 --- a/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotations.java +++ b/core/src/main/java/org/sinytra/adapter/env/util/MixinAnnotations.java @@ -16,6 +16,7 @@ public class MixinAnnotations { public static final String MODIFY_EXPR_VAL = "Lcom/llamalad7/mixinextras/injector/ModifyExpressionValue;"; public static final String MODIFY_EXPR_VAL_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/ModifyExpressionValue"; public static final String MODIFY_RETURN_VAL = "Lcom/llamalad7/mixinextras/injector/ModifyReturnValue;"; + public static final String MODIFY_RETURN_VAL_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/ModifyReturnValue"; public static final String WRAP_OPERATION = "Lcom/llamalad7/mixinextras/injector/wrapoperation/WrapOperation;"; public static final String WRAP_OPERATION_INTERNAL_NAME = "com/llamalad7/mixinextras/injector/wrapoperation/WrapOperation"; public static final String WRAP_WITH_CONDITION = "Lcom/llamalad7/mixinextras/injector/WrapWithCondition;"; diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinTypes.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinTypes.java index 14d7f2fb..840f9fa6 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinTypes.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/MixinTypes.java @@ -15,11 +15,12 @@ public class MixinTypes { // TODO: // MixinConstants.MODIFY_ARGS, MixinConstants.MODIFY_CONST, MixinConstants.WRAP_WITH_CONDITION, - // MixinConstants.MODIFY_RETURN_VAL, MixinConstants.OVERWRITE (dont forget special modifyTarget handling) + // MixinConstants.OVERWRITE (dont forget special modifyTarget handling) // MixinConstants.ACCESSOR public static final MixinType INJECT = new InjectMixin(); public static final MixinType MODIFY_VAR = new ModifyVariableMixin(); public static final MixinType MODIFY_ARG = new ModifyArgMixin(); + public static final MixinType MODIFY_RET = new ModifyReturnValueMixin(); public static final MixinType REDIRECT = new RedirectMixin(); public static final MixinType WRAP_OP = new WrapOperationMixin(); public static final MixinType MODIFY_EXPR_VAL = new ModifyExpressionValueMixin(); @@ -28,6 +29,7 @@ public class MixinTypes { registerMixinType(Inject.class, INJECT); registerMixinType(ModifyVariable.class, MODIFY_VAR); registerMixinType(ModifyArg.class, MODIFY_ARG); + registerMixinType(MixinAnnotations.MODIFY_RETURN_VAL_INTERNAL_NAME, MODIFY_RET); registerMixinType(Redirect.class, REDIRECT); registerMixinType(MixinAnnotations.WRAP_OPERATION_INTERNAL_NAME, WRAP_OP); registerMixinType(MixinAnnotations.MODIFY_EXPR_VAL_INTERNAL_NAME, MODIFY_EXPR_VAL); diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java index c21ad1ff..129cac48 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyExpressionValueMixin.java @@ -26,7 +26,7 @@ import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; public class ModifyExpressionValueMixin implements MixinType { - private final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() .pluralKeys(MixinKeys.TARGET_METHOD, MixinKeys.TARGET_AT) .build(); diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java index d8a3d81f..94820ff9 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/ModifyReturnValueMixin.java @@ -1,32 +1,72 @@ package org.sinytra.adapter.patch.mixin; +import org.objectweb.asm.Type; import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.patch.config.ConfigurationTemplates; import org.sinytra.adapter.patch.config.MutableConfiguration; import org.sinytra.adapter.patch.config.PropertyContainerTemplate; +import org.sinytra.adapter.patch.config.key.MixinKeys; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.resolver.special.InjectorOrdinalResolver; +import org.sinytra.adapter.util.MethodQualifier; + +import java.util.List; + +import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.*; -// TODO public class ModifyReturnValueMixin implements MixinType { + private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + .pluralKeys(MixinKeys.TARGET_METHOD, MixinKeys.TARGET_AT) + .build(); + @Override public PropertyContainerTemplate getConfigurationTemplate() { - return null; + return TEMPLATE; + } + + @Override + public boolean canInject(MixinContext context, Configuration config) { + return !context.classNode().name.toLowerCase().contains("mace"); } @Override public TxResult preProcess(MixinContext context, MutableConfiguration clean, Resolvers resolvers, Processors processors) { resolvers .addBefore(InjectionPointResolver.class, new InjectorOrdinalResolver()); - return null; + + clean.setParameters(MethodParameters.create(context.methodNode(), List.of(SINGLE_ANY, CAPTURED_PARAMS, LOCALS))); + + return TxResult.SUCCESS; } + // TODO Cleanup parameter processing in mixin types + // 1. Method params vs Captured params + reconstruction + // 2. Locals @Override public TxResult postProcess(MixinContext context, Configuration clean, MutableConfiguration dirty, Recipe recipe) { - return null; + if (dirty.getTargetMethod() == null) { + return TxResult.FAIL; + } + + MethodQualifier target = dirty.getTargetMethod(); + List dirtyCaptured = context.methods().resolveCapturedMethodParams(recipe.clean(), recipe.dirty()); + Type modifyingType = Type.getReturnType(target.desc()); + + MethodParameters params = MethodParameters.builder() + .putType(SINGLE_ANY, modifyingType) + .putTypes(CAPTURED_PARAMS, dirtyCaptured) + .put(LOCALS, clean.getParameters().get(LOCALS)) + .build(); + + dirty.setParameters(params); + dirty.setReturnType(modifyingType); + + return TxResult.SUCCESS; } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java index 6ea9b92c..dd7c09d6 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java @@ -32,7 +32,7 @@ import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.METHOD_PARAMS; public class RedirectMixin implements MixinType { - private final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() + private static final PropertyContainerTemplate TEMPLATE = ConfigurationTemplates.MIXIN_AT.extend() .pluralKeys(MixinKeys.TARGET_METHOD) .build(); diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java new file mode 100644 index 00000000..409e8d4e --- /dev/null +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java @@ -0,0 +1,82 @@ +package org.sinytra.adapter.patch.processor; + +import com.mojang.datafixers.util.Pair; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.analysis.params.EnhancedParamsDiff; +import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; +import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.patch.Recipe; +import org.sinytra.adapter.patch.TxResult; +import org.sinytra.adapter.patch.config.Configuration; + +import java.util.List; + +/** + * If a mixin has its parameter changed to a higher class e.g. ServerPlayer -> LivingEntity but + * uses it to call a method that only accepts a ServerPlayer, we have to cast it back. + *

+ * Before: + *

{@code
+ *     private void modify(ServerLevel world, ServerPlayer player, CallbackInfo ci) {
+ *         trigger(player, stack, getDamageValue());
+ *     }
+ * }
+ *

+ * After: + *

{@code
+ *     private void modify(ServerLevel world, LivingEntity player, CallbackInfo ci) {
+ *         trigger((ServerPlayer)player, stack, getDamageValue());
+ * //              ^^^^^^^^^^^^^^ Added cast after param change 
+ *     }
+ * }
+ */ +// TODO Add type safety check +public class ParametersPostProcessor implements Processor { + @Override + public TxResult process(MixinContext context, Configuration dirty, Recipe recipe) { + MethodParameters cleanParams = recipe.clean().getParameters(); + MethodParameters dirtyParams = recipe.clean().getParameters(); + if (!cleanParams.has(MethodParameters.ParamGroup.METHOD_PARAMS) || !dirtyParams.has(MethodParameters.ParamGroup.METHOD_PARAMS)) { + return TxResult.PASS; + } + + List cleanTypes = recipe.clean().getParameters().getTypes(MethodParameters.ParamGroup.METHOD_PARAMS); + List dirtyTypes = recipe.dirty().getParameters().getTypes(MethodParameters.ParamGroup.METHOD_PARAMS); + ParamsDiffSnapshot diff = EnhancedParamsDiff.createLayered(cleanTypes, dirtyTypes); + MethodNode methodNode = context.methodNode(); + LocalVariableLookup lookup = new LocalVariableLookup(context.methodNode()); + + boolean matched = false; + for (Pair replacement : diff.replacements()) { + int ordinal = replacement.getFirst(); + LocalVariableNode node = lookup.getByParameterOrdinal(ordinal); + Type currentType = Type.getType(node.desc); + + for (AbstractInsnNode insn : methodNode.instructions) { + if (!(insn instanceof MethodInsnNode minsn)) continue; + + // Add casts to usage in method calls + List methodArgs = List.of(Type.getArgumentTypes(minsn.desc)); + List callArgs = MethodCallAnalyzer.getMethodCallSrcInsns(methodNode, minsn); + int instanceOffset = minsn.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1; + for (int i = instanceOffset; i < callArgs.size(); i++) { + AbstractInsnNode arg = callArgs.get(i); + if (arg instanceof VarInsnNode varInsn && varInsn.var == node.index) { + Type type = methodArgs.get(i - instanceOffset); + if (!currentType.equals(type)) { + methodNode.instructions.insert(varInsn, new TypeInsnNode(Opcodes.CHECKCAST, type.getInternalName())); + matched = true; + } + } + } + } + } + + return matched ? TxResult.SUCCESS : TxResult.PASS; + } +} diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java b/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java index 0db56a5c..548ba227 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/Processors.java @@ -25,6 +25,8 @@ private void registerDefaultProcessors() { add(new TargetMethodProcessor()); // Mixin method parameters add(new ParametersProcessor()); + // Parameter casts + add(new ParametersPostProcessor()); // Mixin method return type add(new ReturnTypeProcessor()); // Static access modifier diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java index c4c3e8ff..211b749c 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java @@ -25,6 +25,7 @@ import org.sinytra.adapter.patch.resolver.Resolver; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.GeneratedVariables; +import org.sinytra.adapter.util.MethodQualifier; import org.sinytra.adapter.util.SingleValueHandle; import java.util.*; @@ -211,9 +212,60 @@ public Optional apply(MixinContext mixinContext, TargetPair cleanTarget } } + return findByMethodCalls(ordinal, cleanTarget, dirtyTarget); + } + + private static Optional findByMethodCalls(int ordinal, TargetPair cleanTarget, TargetPair dirtyTarget) { + List>> cleanCalls = getBlockCalls(cleanTarget.methodNode()); + List>> dirtyCalls = getBlockCalls(dirtyTarget.methodNode()); + + if (ordinal >= cleanCalls.size()) { + return Optional.empty(); + } + + List cleanCall = cleanCalls.get(ordinal).getSecond(); + for (int i = 0; i < dirtyCalls.size(); i++) { + Pair> dirtyCall = dirtyCalls.get(i); + boolean haveCommon = !Collections.disjoint(cleanCall, dirtyCall.getSecond()); + if (haveCommon) { + return Optional.of(i); + } + } + return Optional.empty(); } + private static List>> getBlockCalls(MethodNode methodNode) { + List>> blockCalls = new ArrayList<>(); + + List minsns = new ArrayList<>(); + for (AbstractInsnNode insn : methodNode.instructions) { + if (insn instanceof MethodInsnNode minsn) { + minsns.add(MethodQualifier.create(minsn).asDescriptor()); + } + if (RETURN_OPCODES.contains(insn.getOpcode())) { + blockCalls.add(Pair.of((InsnNode) insn, minsns)); + minsns = new ArrayList<>(); + } + } + + // Remove non-unique calls + List> values = blockCalls.stream() + .map(Pair::getSecond) + .toList(); + Map counts = new HashMap<>(); + for (List list : values) { + for (String s : list) { + counts.merge(s, 1, Integer::sum); + } + } + for (List list : values) { + list.removeIf(s -> counts.getOrDefault(s, 0) > 1); + } + + return blockCalls; + } + private static List findReturnPrecedingInsns(AbstractInsnNode insn) { List insns = new ArrayList<>(); int maxSize = 6; diff --git a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java index 223b5b5e..c919545d 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java @@ -36,11 +36,11 @@ public class PipelineMethodTransformer implements MethodTransformer { private static final Logger LOGGER = LogUtils.getLogger(); - private final List methodPatches; + private final MethodPatchResolver patchResolver; private final boolean patchesOnly; public PipelineMethodTransformer(List methodPatches, boolean patchesOnly) { - this.methodPatches = methodPatches; + this.patchResolver = new MethodPatchResolver(methodPatches); this.patchesOnly = patchesOnly; } @@ -50,7 +50,7 @@ public PatchResult apply(MixinContext context, Configuration config) { if (cleanTarget == null) return PatchResult.PASS; TargetPair dirtyTarget = context.methods().findOwnMethodPair(context.dirtyLookup(), config.getTargetMethod()); - if (!failsDirtyInjectionCheck(context, config, dirtyTarget) && hasValidSlice(context, config, dirtyTarget)) + if (!this.patchResolver.matches(config) && !failsDirtyInjectionCheck(context, config, dirtyTarget) && hasValidSlice(context, config, dirtyTarget)) return PatchResult.PASS; LOGGER.debug(MIXINPATCH, "Considering method {}", context.getMixinId()); @@ -73,7 +73,7 @@ private PatchResult execute(MixinContext context, Configuration config) { Processors processors = context.getProcessors(); // 0. Add highest priority manual patch resolver - resolvers.addFirst(new MethodPatchResolver(this.methodPatches)); + resolvers.addFirst(this.patchResolver); // 1. Create clean config from validated config MutableConfiguration cleanConfig = config.copy(); diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java index 73afb513..fa51dc18 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/ReplaceParametersTransformer.java @@ -4,12 +4,12 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.ctx.MixinContext; -import org.sinytra.adapter.env.param.Parameters; -import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.env.param.Parameters; +import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.types.BytecodeFixerUpper; import org.sinytra.adapter.types.TypeAdapter; import org.slf4j.Logger; @@ -74,22 +74,12 @@ public PatchResult apply(ClassNode classNode, MethodNode methodNode, MixinContex } } - if (insn instanceof MethodInsnNode minsn) { - // Add casts to usage in method calls - List callArgs = MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); - for (AbstractInsnNode arg : callArgs) { - if (arg instanceof VarInsnNode varInsn && varInsn.var == localVar.index) { - methodNode.instructions.insert(varInsn, new TypeInsnNode(Opcodes.CHECKCAST, originalType.getInternalName())); - } - } - - if (minsn.owner.equals(originalType.getInternalName())) { - List insns = MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); - // Find var load instruction - for (AbstractInsnNode callInsn : insns) { - if (callInsn instanceof VarInsnNode varInsn && varInsn.var == localVar.index) { - minsn.owner = this.type.getInternalName(); - } + if (insn instanceof MethodInsnNode minsn && minsn.owner.equals(originalType.getInternalName())) { + List insns = MethodCallAnalyzer.getMethodCallInsns(methodNode, minsn); + // Find var load instruction + for (AbstractInsnNode callInsn : insns) { + if (callInsn instanceof VarInsnNode varInsn && varInsn.var == localVar.index) { + minsn.owner = this.type.getInternalName(); } } } diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java index 3c2a9ebb..8be5d2e2 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilder.java @@ -1,5 +1,6 @@ package org.sinytra.adapter.transform.patch; +import org.jetbrains.annotations.Nullable; import org.objectweb.asm.commons.InstructionAdapter; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.transform.MethodTransformer; @@ -17,7 +18,7 @@ public interface MethodPatchBuilder { MethodPatchBuilder targetInjectionPoint(String target); - MethodPatchBuilder targetInjectionPoint(String value, String target); + MethodPatchBuilder targetInjectionPoint(String value, @Nullable String target); MethodPatchBuilder targetConstant(double doubleValue); diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java index 688555f2..4970eb00 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchBuilderImpl.java @@ -1,5 +1,6 @@ package org.sinytra.adapter.transform.patch; +import org.jetbrains.annotations.Nullable; import org.objectweb.asm.commons.InstructionAdapter; import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.param.MethodParameters; @@ -12,6 +13,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -60,8 +62,10 @@ public MethodPatchBuilder targetInjectionPoint(String target) { } @Override - public MethodPatchBuilder targetInjectionPoint(String value, String target) { - this.matcher.match(MixinKeys.TARGET_AT, t -> value.equals(t.getValue()) && target.equals(t.getTarget().orElse(null))); + public MethodPatchBuilder targetInjectionPoint(String value, @Nullable String target) { + this.matcher.match(MixinKeys.TARGET_AT, t -> + value.equals(t.getValue()) && Objects.equals(target, t.getTarget().orElse(null)) + ); return this; } diff --git a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java index f38b302e..a68bef58 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java +++ b/core/src/main/java/org/sinytra/adapter/transform/patch/MethodPatchResolver.java @@ -19,6 +19,15 @@ public MethodPatchResolver(List patches) { this.patches = patches; } + public boolean matches(Configuration config) { + for (MethodPatch patch : this.patches) { + if (patch.matcher().match(config)) { + return true; + } + } + return false; + } + @Override public ResolutionResult resolve(MixinContext context, Recipe recipe) { List postChanges = new ArrayList<>(); @@ -36,7 +45,7 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { // Add dynamic properties BiConsumer completer = patch.configCompleter(); completer.accept(recipe.clean(), dirtyConfig); - + postChanges.addAll(patch.transforms()); } } @@ -46,13 +55,13 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { // TODO Might get cancelled by earlier processor recipe.processors().add(new MethodPatchProcessor(postChanges)); } - + // TODO Ugly hardcoding if (dirtyConfig.shouldDelete()) { return ResolutionResult.replace(Configurations.DELETE); } - return ResolutionResult.replace(dirtyConfig); + return ResolutionResult.success(dirtyConfig); } return ResolutionResult.pass(); 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 4dee5305..2f84093d 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 @@ -436,6 +436,16 @@ void testModifiedVariableIndex() throws Exception { ); } + @Test + void testModifiedReturnIndex() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mixin/pipeline/MaceItemMixin", + "rebalanceEquipment", + assertTargetMethod(), + assertInjectionPoint() + ); + } + @Override protected LoadResult load(String className, List allowedMethods) throws Exception { 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 856e3c6a..920a83cb 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 @@ -3,14 +3,14 @@ import com.mojang.logging.LogUtils; import org.apache.commons.lang3.tuple.Pair; import org.assertj.core.api.Assertions; -import org.jetbrains.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.ctx.MixinClassGenerator; import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.provider.ClassLookup; import org.sinytra.adapter.util.provider.ZipClassLookup; @@ -231,11 +231,10 @@ protected AssertCallback assertTargetMethod() { } protected AssertCallback assertInjectionPoint() { - Function> injectionPointExtractor = node -> new AnnotationHandle(node).getNested("at").map(h -> { - String value = h.getValue("value").orElseThrow().get(); - String target = h.getValue("target").map(AnnotationValueHandle::get).orElse(null); - return Pair.of(value, target); - }).orElseThrow(); + Function injectionPointExtractor = node -> new AnnotationHandle(node) + .getNested("at") + .flatMap(h -> AtData.parse(h, s -> s)) + .orElseThrow(); return (patched, expected, env) -> { AnnotationNode patchedMethodAnn = patched.visibleAnnotations.getFirst(); diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/MilkBucketItemMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/MilkBucketItemMixin.java index 0e7ab8b9..060e750f 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/MilkBucketItemMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/MilkBucketItemMixin.java @@ -12,12 +12,25 @@ @Mixin(MilkBucketItem.class) public class MilkBucketItemMixin { // https://github.com/Patbox/brewery/blob/ffdaf1f5298e7ef4f82447546d2afb68286b6acd/src/main/java/eu/pb4/brewery/mixin/MilkBucketItemMixin.java#L30 - @Inject(method = "finishUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;removeAllEffects()Z", shift = At.Shift.BEFORE)) + @Inject( + method = "finishUsingItem", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;removeAllEffects()Z", + shift = At.Shift.BEFORE + ) + ) private void onClearStatusEffect(ItemStack stack, Level level, LivingEntity user, CallbackInfoReturnable cir) { // Noop } - @Inject(method = "finishUsingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;removeEffectsCuredBy(Lnet/neoforged/neoforge/common/EffectCure;)Z")) + @Inject( + method = "finishUsingItem", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;removeEffectsCuredBy(Lnet/neoforged/neoforge/common/EffectCure;)Z" + ) + ) private void onClearStatusEffectExpected(ItemStack stack, Level level, LivingEntity user, CallbackInfoReturnable cir) { // Noop } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/NaturalSpawnerMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/NaturalSpawnerMixin.java index 9bc61f9e..42997d83 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/NaturalSpawnerMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/NaturalSpawnerMixin.java @@ -20,12 +20,27 @@ @Mixin(NaturalSpawner.class) public class NaturalSpawnerMixin { // https://github.com/Globox1997/AdventureZ/blob/7f534296038b61cdfb84d6425b5fcc25b75d86e4/src/main/java/net/adventurez/mixin/SpawnHelperMixin.java#L32 - @Inject(method = "mobsAt", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/levelgen/structure/structures/NetherFortressStructure;FORTRESS_ENEMIES:Lnet/minecraft/util/random/WeightedRandomList;", ordinal = 0), cancellable = true) + @Inject( + method = "mobsAt", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/world/level/levelgen/structure/structures/NetherFortressStructure;FORTRESS_ENEMIES:Lnet/minecraft/util/random/WeightedRandomList;", + ordinal = 0 + ), + cancellable = true + ) private static void getSpawnEntriesMixin(ServerLevel p_220444_, StructureManager p_220445_, ChunkGenerator p_220446_, MobCategory p_220447_, BlockPos p_220448_, @Nullable Holder p_220449_, CallbackInfoReturnable> info) { // Noop } - @Inject(method = "mobsAt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/StructureManager;registryAccess()Lnet/minecraft/core/RegistryAccess;", ordinal = 0), cancellable = true) + @Inject( + method = "mobsAt", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/StructureManager;registryAccess()Lnet/minecraft/core/RegistryAccess;" + ), + cancellable = true + ) private static void getSpawnEntriesMixinExpected(ServerLevel p_220444_, StructureManager p_220445_, ChunkGenerator p_220446_, MobCategory p_220447_, BlockPos p_220448_, @Nullable Holder p_220449_, CallbackInfoReturnable> info) { // Noop } diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ItemInHandRendererMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ItemInHandRendererMixin.java index c76c0408..2769a103 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ItemInHandRendererMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/ItemInHandRendererMixin.java @@ -41,8 +41,7 @@ private boolean renderFirstPersonItemMEV(boolean original) { method = "renderArmWithItem", at = @At( value = "sinytra:INSTANCEOF", - target = "net/minecraft/world/item/CrossbowItem", - ordinal = 1 + target = "net/minecraft/world/item/CrossbowItem" ) ) private boolean renderFirstPersonItemMEVExpected(boolean original) { diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/MaceItemMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/MaceItemMixin.java new file mode 100644 index 00000000..264d5e3d --- /dev/null +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/MaceItemMixin.java @@ -0,0 +1,35 @@ +package org.sinytra.adapter.test.mixin.pipeline; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.MaceItem; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(MaceItem.class) +public class MaceItemMixin { + @ModifyReturnValue( + method = "getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F", + at = @At( + value = "RETURN", + ordinal = 2 + ) + ) + private float rebalanceEquipment(float original, Entity target, float baseAttackDamage, DamageSource damageSource, @Local LivingEntity living) { + return original; + } + + @ModifyReturnValue( + method = "getAttackDamageBonus(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/damagesource/DamageSource;)F", + at = @At( + value = "RETURN", + ordinal = 1 + ) + ) + private float rebalanceEquipmentExpected(float original, Entity target, float baseAttackDamage, DamageSource damageSource, @Local LivingEntity living) { + return original; + } +} From 42810170bed5f7f2603c9850a3e4f0f84dd48b46 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sun, 1 Feb 2026 10:25:34 +0100 Subject: [PATCH 18/27] Remap parsed literal class targets --- .../analysis/method/MethodCallAnalyzer.java | 9 +++- .../sinytra/adapter/env/ann/ClassTarget.java | 47 +++++++------------ .../sinytra/adapter/patch/MixinParser.java | 11 +++-- .../org/sinytra/adapter/patch/Recipe.java | 33 +++++++++---- .../extract/MirrorableExtractMixin.java | 4 +- .../OverloadedInjectionPointSubResolver.java | 14 ++++-- 6 files changed, 64 insertions(+), 54 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java index a3388a04..5f05e910 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/method/MethodCallAnalyzer.java @@ -7,7 +7,6 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.analysis.Frame; import org.objectweb.asm.tree.analysis.SourceValue; -import org.sinytra.adapter.analysis.InsnComparator; import org.sinytra.adapter.analysis.selector.FrameUtil; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; @@ -59,6 +58,12 @@ public static List getMethodCallSrcInsns(MethodNode methodNode @Nullable public static List getMethodCallSrcInsns(MethodNode methodNode, MethodInsnNode minsn, boolean stable) { + // Handle cases where the minsn comes from another method + if (!methodNode.instructions.contains(minsn)) { + List minsns = getMethodCallMinsns(methodNode, MethodQualifier.create(minsn)); + return minsns.size() == 1 ? getMethodCallSrcInsns(methodNode, minsns.getFirst(), stable) : null; + } + List sources = Objects.requireNonNull(getCallSourceValues(methodNode, minsn, stable)); List insns = new ArrayList<>(); @@ -130,7 +135,7 @@ public List getResults() { @Override public SourceValue naryOperation(AbstractInsnNode insn, List values) { - if (InsnComparator.insnEqual(insn, this.targetInsn) && this.results == null) { + if (insn == this.targetInsn && this.results == null) { this.results = values; } return super.naryOperation(insn, values); diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java index d44a6e9f..58b54334 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java @@ -1,10 +1,12 @@ package org.sinytra.adapter.env.ann; +import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Either; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; import org.sinytra.adapter.analysis.selector.AnnotationHandle; import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.env.ctx.RefMapper; import java.util.List; @@ -12,43 +14,21 @@ import static org.sinytra.adapter.env.util.MixinAnnotationConstants.MIXIN_VALUE; public class ClassTarget { - private final AnnotationHandle handle; + private final List types; private final Either>, AnnotationValueHandle>> either; - public ClassTarget(AnnotationHandle handle, Either>, AnnotationValueHandle>> either) { - this.handle = handle; + public ClassTarget(List types, Either>, AnnotationValueHandle>> either) { + this.types = ImmutableList.copyOf(types); this.either = either; } - @Deprecated - public AnnotationHandle getHandle() { - return this.handle; - } - - @Deprecated - public AnnotationValueHandle getValueHandle() { - if (this.either.left().isPresent()) { - return this.either.left().orElseThrow(); - } - return this.either.right().orElseThrow(); - } - public List getTypes() { - return this.either.map(AnnotationValueHandle::get, h -> h.get() - .stream() - .map(Type::getObjectType) - .toList() - ); + return this.types; } @Nullable public Type getSingle() { - List types = this.either.map(AnnotationValueHandle::get, h -> h.get() - .stream() - .map(Type::getObjectType) - .toList() - ); - return types.size() != 1 ? null : types.getFirst(); + return this.types.size() != 1 ? null : this.types.getFirst(); } public void set(Type type) { @@ -57,11 +37,16 @@ public void set(Type type) { } @Nullable - public static ClassTarget parse(AnnotationHandle handle) { + public static ClassTarget parse(AnnotationHandle handle, RefMapper mapper) { return handle.>getValue(MIXIN_VALUE) - .>, AnnotationValueHandle>>>map(Either::left) - .or(() -> handle.>getValue(MIXIN_TARGETS).map(Either::right)) - .map(v -> new ClassTarget(handle, v)) + .map(v -> new ClassTarget(v.get(), Either.left(v))) + .or(() -> handle.>getValue(MIXIN_TARGETS).map(v -> { + List types = v.get().stream() + .map(mapper::remap) + .map(Type::getObjectType) + .toList(); + return new ClassTarget(types, Either.right(v)); + })) .orElse(null); } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java index 2e6c1c37..8c5e9c99 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java +++ b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java @@ -25,13 +25,14 @@ public class MixinParser { @Nullable public static MixinClassHandle parseMixins(ClassNode classNode, PatchEnvironment environment) { - ClassTarget cls = parseTargetClass(classNode); + RefMapper mapper = ref -> environment.refmapHolder().remap(classNode.name, ref); + + ClassTarget cls = parseTargetClass(classNode, mapper); if (cls == null) return null; - RefMapper refMapper = ref -> environment.refmapHolder().remap(classNode.name, ref); List methods = new ArrayList<>(); for (MethodNode method : classNode.methods) { - MixinMethodHandle handle = parseMixin(cls, method, refMapper); + MixinMethodHandle handle = parseMixin(cls, method, mapper); if (handle != null) { methods.add(handle); } @@ -66,13 +67,13 @@ public static MixinMethodHandle parseMixin(ClassTarget cls, MethodNode method, R } @Nullable - private static ClassTarget parseTargetClass(ClassNode classNode) { + private static ClassTarget parseTargetClass(ClassNode classNode, RefMapper mapper) { if (classNode.invisibleAnnotations == null) return null; for (AnnotationNode annotation : classNode.invisibleAnnotations) { if (annotation.desc.equals(MixinAnnotations.MIXIN)) { AnnotationHandle ann = new AnnotationHandle(annotation); - return ClassTarget.parse(ann); + return ClassTarget.parse(ann, mapper); } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/Recipe.java b/core/src/main/java/org/sinytra/adapter/patch/Recipe.java index 835149d2..a491a19a 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/Recipe.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Recipe.java @@ -1,13 +1,13 @@ package org.sinytra.adapter.patch; import com.google.common.base.Suppliers; -import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import org.sinytra.adapter.env.ann.AtData; +import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.processor.Processors; import org.sinytra.adapter.patch.resolver.Resolvers; -import org.sinytra.adapter.env.ctx.TargetPair; -import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import java.util.Objects; import java.util.Optional; @@ -26,6 +26,10 @@ public final class Recipe { private final Processors processors; private final MixinContext context; + private final Supplier cleanTarget; + private final Supplier newCleanTarget; + private final Supplier dirtyTarget; + private final Supplier cleanLocalsTableCache; private final Supplier dirtyLocalsTableCache; @@ -40,6 +44,19 @@ public Recipe(Configuration clean, Configuration dirty, Resolvers resolvers, Pro this.processors = processors; this.context = context; + this.cleanTarget = Suppliers.memoize(() -> { + if (clean.getTargetMethod() == null) return null; + return context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); + }); + this.newCleanTarget = Suppliers.memoize(() -> { + if (clean.getTargetMethod() == null) return null; + return context.methods().findOwnMethodPair(context.dirtyLookup(), clean.getTargetMethod()); + }); + this.dirtyTarget = Suppliers.memoize(() -> { + if (dirty.getTargetMethod() == null) return null; + return context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + }); + this.cleanLocalsTableCache = Suppliers.memoize(() -> Optional.ofNullable(getCleanTarget()) .map(pair -> new LocalVariableLookup(pair.methodNode())) .orElse(null)); @@ -60,20 +77,16 @@ public Recipe withDirtyConfig(Configuration dirty) { return new Recipe(this.clean, dirty, this.resolvers, this.processors, this.context); } - // TODO Cache public TargetPair getCleanTarget() { - if (clean.getTargetMethod() == null) return null; - return context.methods().findOwnMethodPair(context.cleanLookup(), clean.getTargetMethod()); + return this.cleanTarget.get(); } public TargetPair getNewCleanTarget() { - if (clean.getTargetMethod() == null) return null; - return context.methods().findOwnMethodPair(context.dirtyLookup(), clean.getTargetMethod()); + return this.newCleanTarget.get(); } public TargetPair getDirtyTarget() { - if (dirty.getTargetMethod() == null) return null; - return context.methods().findOwnMethodPair(context.dirtyLookup(), dirty.getTargetMethod()); + return this.dirtyTarget.get(); } public boolean hasInjectionPointValue(String value) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java index 88ccfc25..3a098e4c 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java @@ -6,14 +6,14 @@ import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.env.util.TypeConstants; import org.sinytra.adapter.patch.Recipe; -import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; -import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; import org.sinytra.adapter.util.OpcodeUtil; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java index 19ec6cb7..d1f01c99 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/injection/OverloadedInjectionPointSubResolver.java @@ -7,7 +7,6 @@ import org.sinytra.adapter.env.ann.AtData; import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.TargetPair; -import org.sinytra.adapter.env.util.MixinAnnotationConstants; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; @@ -17,10 +16,17 @@ import java.util.List; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE; +import static org.sinytra.adapter.env.util.MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN; + public class OverloadedInjectionPointSubResolver implements SubResolver { @Nullable @Override public Configuration resolve(MixinContext context, Recipe recipe) { + AtData at = recipe.clean().getAtData(); + if (at == null || !at.getValue().equals(AT_VAL_INVOKE) && !at.getValue().equals(AT_VAL_INVOKE_ASSIGN)) + return null; + TargetPair cleanPair = recipe.getCleanTarget(); if (cleanPair == null) return null; @@ -28,7 +34,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { if (dirtyPair == null) return null; // Temporarily modify @At data to target INVOKE if originally using INVOKE_ASSIGN - AtData tempAt = getInvokeAtData(recipe.clean().getAtData()); + AtData tempAt = getInvokeAtData(at); AbstractInsnNode cleanInsn = context.methods().findInjectionTargetInsn(cleanPair, tempAt); if (!(cleanInsn instanceof MethodInsnNode cleanMinsn)) return null; MethodQualifier cleanQualifier = MethodQualifier.create(cleanMinsn); @@ -64,8 +70,8 @@ public Configuration resolve(MixinContext context, Recipe recipe) { } private AtData getInvokeAtData(AtData at) { - if (at.getValue().equals(MixinAnnotationConstants.AT_VAL_INVOKE_ASSIGN)) { - return at.withValue(MixinAnnotationConstants.AT_VAL_INVOKE); + if (at.getValue().equals(AT_VAL_INVOKE_ASSIGN)) { + return at.withValue(AT_VAL_INVOKE); } return at; } From 35d884ac133b0f8e582f060d961488caa0ebf6fc Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sun, 1 Feb 2026 11:18:28 +0100 Subject: [PATCH 19/27] Parse mixins after running class transformers --- .../sinytra/adapter/env/ann/ClassTarget.java | 3 ++- .../sinytra/adapter/patch/MixinParser.java | 16 +++++++++----- .../org/sinytra/adapter/patch/Patcher.java | 21 +++++++++++-------- .../cls/DynamicAnonClassIndexPatch.java | 6 +++--- .../sinytra/adapter/util/MethodQualifier.java | 4 ++-- .../sinytra/adapter/test/mixin/GuiMixin.java | 19 +++++++++++++++-- 6 files changed, 47 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java index 58b54334..edf6ba7f 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java +++ b/core/src/main/java/org/sinytra/adapter/env/ann/ClassTarget.java @@ -14,7 +14,7 @@ import static org.sinytra.adapter.env.util.MixinAnnotationConstants.MIXIN_VALUE; public class ClassTarget { - private final List types; + private List types; private final Either>, AnnotationValueHandle>> either; public ClassTarget(List types, Either>, AnnotationValueHandle>> either) { @@ -32,6 +32,7 @@ public Type getSingle() { } public void set(Type type) { + this.types = List.of(type); this.either.ifLeft(h -> h.set(List.of(type))) .ifRight(h -> h.set(List.of(type.getInternalName()))); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java index 8c5e9c99..e99b94ac 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java +++ b/core/src/main/java/org/sinytra/adapter/patch/MixinParser.java @@ -23,12 +23,14 @@ public class MixinParser { - @Nullable - public static MixinClassHandle parseMixins(ClassNode classNode, PatchEnvironment environment) { - RefMapper mapper = ref -> environment.refmapHolder().remap(classNode.name, ref); + public static ClassTarget prepareMixinClass(ClassNode classNode, PatchEnvironment environment) { + RefMapper mapper = mapperFor(classNode, environment); + return parseTargetClass(classNode, mapper); + } - ClassTarget cls = parseTargetClass(classNode, mapper); - if (cls == null) return null; + @Nullable + public static MixinClassHandle parseMixins(ClassTarget cls, ClassNode classNode, PatchEnvironment environment) { + RefMapper mapper = mapperFor(classNode, environment); List methods = new ArrayList<>(); for (MethodNode method : classNode.methods) { @@ -80,6 +82,10 @@ private static ClassTarget parseTargetClass(ClassNode classNode, RefMapper mappe return null; } + private static RefMapper mapperFor(ClassNode classNode, PatchEnvironment environment) { + return ref -> environment.refmapHolder().remap(classNode.name, ref); + } + public record MixinMethodHandle(MixinType mixinType, MethodNode methodNode, AnnotationHandle methodAnnotation, PropertyContainer properties) { } diff --git a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java index 48a7880e..bae47c01 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java @@ -40,11 +40,9 @@ private Patcher(PatchEnvironment environment, List classPatche } public PatchResult process(ClassNode classNode) { - // Parse mixin data - MixinParser.MixinClassHandle mixinClass = MixinParser.parseMixins(classNode, this.environment); - if (mixinClass == null) return PatchResult.PASS; + // Parse class data + ClassTarget classTarget = MixinParser.prepareMixinClass(classNode, this.environment); - ClassTarget classTarget = mixinClass.classTarget(); PatchResult result = PatchResult.PASS; PatchContextImpl context = new PatchContextImpl(classNode, classTarget.getTypes(), this.environment); @@ -53,6 +51,11 @@ public PatchResult process(ClassNode classNode) { result = result.or(patch.apply(classNode, classTarget, context)); } + // Parse mixin methods + // Note: Parsing is split in two to account for potential changes to mixin methods by ClassTransformers + MixinParser.MixinClassHandle mixinClass = MixinParser.parseMixins(classTarget, classNode, this.environment); + if (mixinClass == null) return result; + // Mixin-level transformations for (MixinParser.MixinMethodHandle mixin : mixinClass.mixins()) { PatchResult subResult = processMixin(classNode, classTarget, context, mixin); @@ -93,7 +96,7 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P LOGGER.debug(MIXINPATCH, "Skipping mixin {} due to failed preProcess", mixinId); return PatchResult.PASS; } - + // << RUN LOADED PHASE for (MethodTransformer transformer : getTransformers(TxPhase.LOADED)) { PatchResult txResult = transformer.apply(mixinContext, configuration); @@ -133,22 +136,22 @@ public static class Builder { public Builder(PatchEnvironment environment) { this.environment = environment; } - + public Builder classTransformer(ClassTransformer transformer) { this.classTransformers.add(transformer); return this; } - + public Builder classTransformers(List transformers) { this.classTransformers.addAll(transformers); return this; } - + public Builder methodTransformer(TxPhase phase, MethodTransformer transformer) { this.methodTransformers.put(phase, transformer); return this; } - + public Builder methodTransformers(Multimap transformers) { this.methodTransformers.putAll(transformers); return this; diff --git a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java index 43706bde..bd98c212 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java +++ b/core/src/main/java/org/sinytra/adapter/transform/cls/DynamicAnonClassIndexPatch.java @@ -51,7 +51,7 @@ public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchCont if (!inner.name.equals(target) && cleanOuterMethod.matches(null, inner.outerMethod, inner.outerMethodDesc)) { classTarget.set(Type.getObjectType(inner.name)); - stripOwnerFromMixinTargets(classNode, classTarget, context, inner.name); + updateMixinTargetOwners(classNode, classTarget, context, inner.name); return PatchResult.APPLY; } } @@ -60,13 +60,13 @@ public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchCont return PatchResult.PASS; } - private static void stripOwnerFromMixinTargets(ClassNode classNode, ClassTarget classTarget, PatchContext context, String newOwner) { + private static void updateMixinTargetOwners(ClassNode classNode, ClassTarget classTarget, PatchContext context, String newOwner) { for (MethodNode method : classNode.methods) { MixinParser.MixinMethodHandle handle = MixinParser.parseMixin(classTarget, method, context); if (handle == null) continue; handle.properties().getProperty(MixinKeys.TARGET_METHOD) - .map(q -> q.withOwner(newOwner)) + .map(q -> q.withOwner(Type.getObjectType(newOwner))) .map(MixinKeys.TARGET_METHOD::serialize) .ifPresent(q -> handle.methodAnnotation().setOrAppendNonNull(MixinKeys.TARGET_METHOD.name(), q)); } diff --git a/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java index 911c6aa6..f9a5f18b 100644 --- a/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java +++ b/core/src/main/java/org/sinytra/adapter/util/MethodQualifier.java @@ -73,8 +73,8 @@ public String asDescriptor() { return result + this.name + (this.desc != null ? this.desc : ""); } - public MethodQualifier withOwner(String owner) { - return new MethodQualifier(owner, this.name, this.desc); + public MethodQualifier withOwner(@Nullable Type owner) { + return new MethodQualifier(owner == null ? null : owner.getDescriptor(), this.name, this.desc); } public MethodQualifier ignoreDesc() { 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 0f43ab4c..61c95cc1 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 @@ -23,12 +23,27 @@ @Mixin(Gui.class) public class GuiMixin { // https://github.com/juancarloscp52/BedrockIfy/blob/c4bc4f425adffaab1a7bdf4c8740f12281e94668/src/main/java/me/juancarloscp52/bedrockify/mixin/client/features/screenSafeArea/InGameHudMixin.java#L122 - @ModifyArg(method = "renderPlayerHealth", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lnet/minecraft/resources/ResourceLocation;IIII)V"), index = 2) + @ModifyArg( + method = "renderPlayerHealth", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lnet/minecraft/resources/ResourceLocation;IIII)V" + ) + , + index = 2 + ) public int modifyTextureStatusBar(int y) { return y; } - @ModifyArg(method = "renderAirLevel(Lnet/minecraft/client/gui/GuiGraphics;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lnet/minecraft/resources/ResourceLocation;IIII)V"), index = 2) + @ModifyArg( + method = "renderAirLevel(Lnet/minecraft/client/gui/GuiGraphics;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/GuiGraphics;blitSprite(Lnet/minecraft/resources/ResourceLocation;IIII)V" + ), + index = 2 + ) public int modifyTextureStatusBarExpected(int y) { return y; } From bf0ea6a97234ba97da1c170e74be5fd11ca9e12f Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sun, 1 Feb 2026 12:10:40 +0100 Subject: [PATCH 20/27] Improve overloaded target resolution --- .../adapter/patch/mixin/RedirectMixin.java | 11 +++----- .../processor/ParametersPostProcessor.java | 3 ++- .../extract/MirrorableExtractMixin.java | 3 ++- .../resolver/target/TargetMethodResolver.java | 2 +- .../target/TargetMethodSubResolvers.java | 9 ++++++- .../test/mixin/DynamicMixinPatchTest.java | 10 +++++++ .../adapter/test/mixin/pipeline/GuiMixin.java | 27 +++++++++++++++++++ 7 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiMixin.java diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java index dd7c09d6..4786f123 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java @@ -61,14 +61,11 @@ public TxResult preProcess(MixinContext context, MutableConfiguration clean, Res if (targetDesc == null) return TxResult.FAIL; - TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), targetDesc); - if (cleanTarget == null) - return TxResult.FAIL; - + List methodParams = Parameters.getParameterTypes(context.methodNode().desc); List callTypes = Parameters.getParameterTypes(targetDesc.desc()); - if (!MethodHelper.isStatic(cleanTarget.methodNode())) { - Type owner = Type.getObjectType(cleanTarget.classNode().name); - callTypes.addFirst(owner); + boolean isStatic = methodParams.size() >= callTypes.size() && methodParams.subList(0, callTypes.size()).equals(callTypes); + if (!isStatic) { + callTypes.addFirst(methodParams.getFirst()); } List methodTypes = Parameters.getParameterTypes(context.methodNode().desc); diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java index 409e8d4e..c6e4356e 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersPostProcessor.java @@ -10,6 +10,7 @@ import org.sinytra.adapter.analysis.params.ParamsDiffSnapshot; import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; +import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; @@ -61,7 +62,7 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe if (!(insn instanceof MethodInsnNode minsn)) continue; // Add casts to usage in method calls - List methodArgs = List.of(Type.getArgumentTypes(minsn.desc)); + List methodArgs = Parameters.getParameterTypes(minsn.desc); List callArgs = MethodCallAnalyzer.getMethodCallSrcInsns(methodNode, minsn); int instanceOffset = minsn.getOpcode() == Opcodes.INVOKESTATIC ? 0 : 1; for (int i = instanceOffset; i < callArgs.size(); i++) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java index 3a098e4c..0b22733a 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java @@ -11,6 +11,7 @@ import org.sinytra.adapter.env.ctx.PatchEnvironment; import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.env.util.MixinAnnotations; import org.sinytra.adapter.env.util.TypeConstants; import org.sinytra.adapter.patch.Recipe; @@ -62,7 +63,7 @@ public static PatchResult apply(MixinContext context, Recipe recipe, String dest environment.refmapHolder().copyEntries(classNode.name, generatedTarget.name); // Generate a method with the same injector annotation String name = methodNode.name + "$adapter$mirror$" + AdapterUtil.randomString(5); - List originalParams = List.of(Type.getArgumentTypes(methodNode.desc)); + List originalParams = Parameters.getParameterTypes(methodNode.desc); List newParams = ImmutableList.builder().add(Type.getArgumentTypes(destinationMethodInvocation.desc)).add(TypeConstants.CI_TYPE).build(); // Make sure we have all required params if (!new HashSet<>(newParams).containsAll(originalParams)) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java index fa1cbb97..f10ab498 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodResolver.java @@ -1,10 +1,10 @@ package org.sinytra.adapter.patch.resolver.target; import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.resolver.CompoundResolver; -import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.util.MethodQualifier; public class TargetMethodResolver extends CompoundResolver { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java index ab425e26..6ee518a4 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java @@ -9,6 +9,7 @@ import org.objectweb.asm.tree.MethodNode; import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.ctx.TargetPair; +import org.sinytra.adapter.env.param.Parameters; import org.sinytra.adapter.patch.Recipe; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.config.MutableConfiguration; @@ -85,7 +86,7 @@ private static Configuration resolveReplacementCandidate(MixinContext context, R Resolver resolver = recipe.resolvers().get(InjectionPointResolver.class); List> valid = methods.stream() - .sorted(Comparator.comparing(m -> m.desc).reversed()) + .sorted(Comparator.comparingInt(m -> Parameters.getParameterTypes(m.desc).size()).reversed()) .>flatMap(m -> { Configuration dirtyCopy = recipe.dirty().copy().setTargetMethod(m); return resolver.resolve(context, recipe.withDirtyConfig(dirtyCopy)) @@ -107,6 +108,12 @@ private static Configuration resolveReplacementCandidate(MixinContext context, R .setTargetMethod(nonDeprecated.getFirst()); } + // Best effort: Handle cases where the target method is overloaded, but the mixin does not specify the target descriptor, + // resulting in ambigous targets. So we just pick the one with the most parameters; + if (!valid.isEmpty()) { + return valid.getFirst().getSecond(); + } + return null; } 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 2f84093d..38192547 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 @@ -446,6 +446,16 @@ void testModifiedReturnIndex() throws Exception { ); } + @Test + void testAmbigousOverloadedTarget() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mixin/pipeline/GuiMixin", + "renderSelectedItemName", + assertTargetMethod(), + assertInjectionPoint() + ); + } + @Override protected LoadResult load(String className, List allowedMethods) throws Exception { ClassNode patched = loadClass(className); diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiMixin.java new file mode 100644 index 00000000..cb4b60ae --- /dev/null +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/pipeline/GuiMixin.java @@ -0,0 +1,27 @@ +package org.sinytra.adapter.test.mixin.pipeline; + +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +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.callback.CallbackInfo; + +@Mixin(Gui.class) +public class GuiMixin { + @Inject( + method = "renderSelectedItemName", + at = @At("HEAD") + ) + public void renderSelectedItemName(GuiGraphics guiGraphics, CallbackInfo ci) { + + } + + @Inject( + method = "renderSelectedItemName(Lnet/minecraft/client/gui/GuiGraphics;I)V", + at = @At("HEAD") + ) + public void renderSelectedItemNameExpected(GuiGraphics guiGraphics, int adapter_injected_1, CallbackInfo ci) { + + } +} From f413db421a9fbef85c28302e4f9d4735228b9ad5 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sun, 1 Feb 2026 13:01:12 +0100 Subject: [PATCH 21/27] Fix LVLookup incorrect parameter ordinals --- .../sinytra/adapter/analysis/locals/LocalVariableLookup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java index fa480167..9c901678 100644 --- a/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java +++ b/core/src/main/java/org/sinytra/adapter/analysis/locals/LocalVariableLookup.java @@ -46,7 +46,7 @@ public int getOrdinal(LocalVariableNode node) { } public int getParameterOrdinal(LocalVariableNode node) { - return getOrdinal(node) + (this.isNonStatic ? 1 : 0); + return getOrdinal(node) - (this.isNonStatic ? 1 : 0); } public LocalVariableNode getLast() { From 1c09477734e2579f441ab82a77b407ae7f780a8b Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sun, 1 Feb 2026 15:24:31 +0100 Subject: [PATCH 22/27] Fix Shared locals param capture --- .../sinytra/adapter/env/param/MethodParameters.java | 4 ++-- .../org/sinytra/adapter/env/param/Parameter.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java b/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java index 52a91a6f..2224ded9 100644 --- a/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java @@ -17,13 +17,13 @@ public enum ParamGroupType { public record ParamGroup(ParamGroupType type, String name, Predicate predicate) { public static final ParamGroup METHOD_PARAMS = new ParamGroup(ParamGroupType.VARIABLE, "method_params", i -> true); - public static final ParamGroup CAPTURED_PARAMS = new ParamGroup(ParamGroupType.VARIABLE, "captured_params", i -> !i.isLocal()); + public static final ParamGroup CAPTURED_PARAMS = new ParamGroup(ParamGroupType.VARIABLE, "captured_params", i -> !i.isLocalOrShare()); public static final ParamGroup SINGLE_ANY = new ParamGroup(ParamGroupType.SINGLE, "single_any", i -> true); public static final ParamGroup CI_CIR = new ParamGroup(ParamGroupType.SINGLE, "ci_cir", i -> i.getType().equals(TypeConstants.CI_TYPE) || i.getType().equals(TypeConstants.CIR_TYPE)); public static final ParamGroup OPERATION = new ParamGroup(ParamGroupType.SINGLE, "operation", i -> i.getType().equals(TypeConstants.OPERATION_TYPE)); - public static final ParamGroup LOCALS = new ParamGroup(ParamGroupType.VARIABLE, "locals", Parameter::isLocal); + public static final ParamGroup LOCALS = new ParamGroup(ParamGroupType.VARIABLE, "locals", Parameter::isLocalOrShare); } private final Map> groups; diff --git a/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java b/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java index 6933ac1b..5acf64ba 100644 --- a/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java @@ -25,15 +25,23 @@ public List getAnnotations() { return this.annotations; } + public boolean isLocalOrShare() { + return isLocal() || isShare(); + } + public boolean isLocal() { return hasAnnotation(MixinAnnotations.LOCAL); } + public boolean isShare() { + return hasAnnotation(MixinAnnotations.SHARE); + } + public boolean hasAnnotation(String desc) { return this.annotations.stream() .anyMatch(annotation -> annotation.getDesc().equals(desc)); } - + public Builder extend() { Builder builder = builder(this.type); this.annotations.forEach(builder::annotate); @@ -47,7 +55,7 @@ public static Parameter simple(Type type) { public static Builder builder(String typeDesc) { return builder(Type.getType(typeDesc)); } - + public static Builder builder(Type type) { return new Builder(type); } From 777ec68c9b3a5ea60e27255090cf1b2b5aab3042 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Sun, 1 Feb 2026 15:55:00 +0100 Subject: [PATCH 23/27] Use clear target in redirect when possible --- .../org/sinytra/adapter/patch/mixin/RedirectMixin.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java index 4786f123..056ff73f 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/RedirectMixin.java @@ -63,7 +63,7 @@ public TxResult preProcess(MixinContext context, MutableConfiguration clean, Res List methodParams = Parameters.getParameterTypes(context.methodNode().desc); List callTypes = Parameters.getParameterTypes(targetDesc.desc()); - boolean isStatic = methodParams.size() >= callTypes.size() && methodParams.subList(0, callTypes.size()).equals(callTypes); + boolean isStatic = isStaticRedirect(context, targetDesc, methodParams, callTypes); if (!isStatic) { callTypes.addFirst(methodParams.getFirst()); } @@ -111,4 +111,12 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo return TxResult.SUCCESS; } + + private boolean isStaticRedirect(MixinContext context, MethodQualifier targetDesc, List methodParams, List callTypes) { + TargetPair cleanTarget = context.methods().findOwnMethodPair(context.cleanLookup(), targetDesc); + if (cleanTarget != null) { + return MethodHelper.isStatic(cleanTarget.methodNode()); + } + return methodParams.size() >= callTypes.size() && methodParams.subList(0, callTypes.size()).equals(callTypes); + } } From 7f286e955e622561519593e0d781f040c5fe8053 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Mon, 2 Feb 2026 16:11:34 +0100 Subject: [PATCH 24/27] Pipeline Auditing --- .../org/sinytra/adapter/env/ctx/Auditor.java | 2 +- .../sinytra/adapter/env/ctx/MixinContext.java | 22 +++++++++++++++++-- .../sinytra/adapter/env/param/Annotation.java | 15 ++++++++++++- .../adapter/env/param/MethodParameters.java | 10 ++++----- .../sinytra/adapter/env/param/Parameter.java | 14 ++---------- .../sinytra/adapter/env/param/Parameters.java | 6 ++--- .../org/sinytra/adapter/patch/Patcher.java | 12 +++++++--- .../adapter/patch/mixin/InjectMixin.java | 18 ++++++++++++++- .../processor/DisableMixinProcessor.java | 6 ++--- .../patch/processor/MixinTypeProcessor.java | 2 +- .../patch/processor/ParametersProcessor.java | 2 ++ .../patch/processor/PropertyProcessor.java | 3 +++ .../processor/StaticAccessProcessor.java | 4 ++-- .../extract/ExtractMixinProcessor.java | 7 ++---- .../extract/MirrorableExtractMixin.java | 2 ++ .../wrapop/WrapOpParamsProcessor.java | 2 +- .../patch/resolver/CompoundResolver.java | 2 ++ .../special/InjectorOrdinalResolver.java | 2 +- .../special/ModifyVarAtReturnResolver.java | 6 ++--- .../target/SplitMethodCancellationHelper.java | 2 +- .../target/SplitTargetMethodSubResolver.java | 2 +- .../target/TargetMethodSubResolvers.java | 5 ++++- .../transform/PipelineMethodTransformer.java | 4 ++++ .../transform/param/TransformParameters.java | 7 +++--- .../LocalCaptureUpgradeTransformer.java | 7 +++--- 25 files changed, 110 insertions(+), 54 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/Auditor.java b/core/src/main/java/org/sinytra/adapter/env/ctx/Auditor.java index 59f8438e..318d2d7c 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/Auditor.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/Auditor.java @@ -1,5 +1,5 @@ package org.sinytra.adapter.env.ctx; public interface Auditor { - void recordAudit(Object transform, String message, Object... args); + void recordAudit(Object actor, String message, Object... args); } diff --git a/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java index 79cc74df..b9c7f357 100644 --- a/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java +++ b/core/src/main/java/org/sinytra/adapter/env/ctx/MixinContext.java @@ -14,6 +14,7 @@ import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.provider.ClassLookup; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -28,6 +29,7 @@ public class MixinContext implements RefMapper, Auditor { private final AnnotationHandle methodAnnotation; private final AnnotationHandle injectionPointAnnotation; + private final List auditContext = new ArrayList<>(); private final String mixinId; private final MethodHelper methodHelper; @@ -133,9 +135,25 @@ public List targetTypes() { public PatchEnvironment environment() { return patchContext().environment(); } + + public void pushAudit(Object actor) { + this.auditContext.add(actor); + } + + public void popAudit() { + this.auditContext.removeLast(); + } + + public void recordCtxAudit(String message, Object... args) { + if (this.auditContext.isEmpty()) { + throw new RuntimeException("Missing audit context object"); + } + Object ctx = this.auditContext.getLast(); + recordAudit(ctx, message, args); + } @Override - public void recordAudit(Object transform, String message, Object... args) { - environment().auditTrail().recordAudit(transform, this, message, args); + public void recordAudit(Object actor, String message, Object... args) { + environment().auditTrail().recordAudit(actor, this, message, args); } } diff --git a/core/src/main/java/org/sinytra/adapter/env/param/Annotation.java b/core/src/main/java/org/sinytra/adapter/env/param/Annotation.java index f4f05200..bd376cfb 100644 --- a/core/src/main/java/org/sinytra/adapter/env/param/Annotation.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Annotation.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Objects; public class Annotation { private final String desc; @@ -35,7 +36,19 @@ public String getDesc() { public boolean isVisible() { return this.visible; } - + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Annotation that = (Annotation) o; + return visible == that.visible && Objects.equals(desc, that.desc) && Objects.equals(properties, that.properties); + } + + @Override + public int hashCode() { + return Objects.hash(desc, visible, properties); + } + public static Annotation parse(AnnotationNode node, boolean visible) { Builder builder = builder(node.desc).visible(visible); if (node.values != null) { diff --git a/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java b/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java index 2224ded9..584cf812 100644 --- a/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/MethodParameters.java @@ -20,8 +20,8 @@ public record ParamGroup(ParamGroupType type, String name, Predicate public static final ParamGroup CAPTURED_PARAMS = new ParamGroup(ParamGroupType.VARIABLE, "captured_params", i -> !i.isLocalOrShare()); public static final ParamGroup SINGLE_ANY = new ParamGroup(ParamGroupType.SINGLE, "single_any", i -> true); - public static final ParamGroup CI_CIR = new ParamGroup(ParamGroupType.SINGLE, "ci_cir", i -> i.getType().equals(TypeConstants.CI_TYPE) || i.getType().equals(TypeConstants.CIR_TYPE)); - public static final ParamGroup OPERATION = new ParamGroup(ParamGroupType.SINGLE, "operation", i -> i.getType().equals(TypeConstants.OPERATION_TYPE)); + public static final ParamGroup CI_CIR = new ParamGroup(ParamGroupType.SINGLE, "ci_cir", i -> i.type().equals(TypeConstants.CI_TYPE) || i.type().equals(TypeConstants.CIR_TYPE)); + public static final ParamGroup OPERATION = new ParamGroup(ParamGroupType.SINGLE, "operation", i -> i.type().equals(TypeConstants.OPERATION_TYPE)); public static final ParamGroup LOCALS = new ParamGroup(ParamGroupType.VARIABLE, "locals", Parameter::isLocalOrShare); } @@ -56,7 +56,7 @@ public boolean has(ParamGroup group) { public List getTypes(ParamGroup group) { return get(group).stream() - .map(Parameter::getType) + .map(Parameter::type) .toList(); } @@ -87,7 +87,7 @@ public void set(ParamGroup group, List params) { public List mergeTypes() { return merge().stream() - .map(Parameter::getType) + .map(Parameter::type) .toList(); } @@ -151,7 +151,7 @@ private static MethodParameters create(List params, List // Two subsequent groups cannot both match a parameter else { throw new IllegalStateException("Ambiguous match for param %s in groups %s and %s" - .formatted(param.getType(), group.name(), groups.get(groupIndex + 1).name())); + .formatted(param.type(), group.name(), groups.get(groupIndex + 1).name())); } } diff --git a/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java b/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java index 5acf64ba..647c1df6 100644 --- a/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Parameter.java @@ -8,27 +8,17 @@ import java.util.List; import java.util.function.Consumer; -public class Parameter { - private final Type type; - private final List annotations; +public record Parameter(Type type, List annotations) { public Parameter(Type type, List annotations) { this.type = type; this.annotations = ImmutableList.copyOf(annotations); } - public Type getType() { - return this.type; - } - - public List getAnnotations() { - return this.annotations; - } - public boolean isLocalOrShare() { return isLocal() || isShare(); } - + public boolean isLocal() { return hasAnnotation(MixinAnnotations.LOCAL); } diff --git a/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java b/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java index 7eb37cfa..ec128050 100644 --- a/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java +++ b/core/src/main/java/org/sinytra/adapter/env/param/Parameters.java @@ -63,7 +63,7 @@ public static Map> gatherVarMappings(MethodNode LocalVariableNode newVar = lookup.getByParameterOrdinal(newIndex); if (newVar == null) return null; - return Pair.of(oldVar.index, Pair.of(newVar.index, entry.getValue().getType())); + return Pair.of(oldVar.index, Pair.of(newVar.index, entry.getValue().type())); }) .filter(Objects::nonNull) .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond)); @@ -87,7 +87,7 @@ public static void applyAnnotations(MethodNode method, List parameter // TODO Always re-apply all annotations or? // Remove old annotations - Set descs = param.getAnnotations().stream().map(Annotation::getDesc).collect(Collectors.toSet()); + Set descs = param.annotations().stream().map(Annotation::getDesc).collect(Collectors.toSet()); final int finalI = i; Stream.of(method.visibleParameterAnnotations, method.invisibleParameterAnnotations) .filter(Objects::nonNull) @@ -95,7 +95,7 @@ public static void applyAnnotations(MethodNode method, List parameter .filter(Objects::nonNull) .forEach(list -> list.removeIf(n -> descs.contains(n.desc))); - for (Annotation annotation : param.getAnnotations()) { + for (Annotation annotation : param.annotations()) { AnnotationVisitor visitor = method.visitParameterAnnotation(i, annotation.getDesc(), annotation.isVisible()); annotation.accept(visitor); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java index bae47c01..08833a3c 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/Patcher.java +++ b/core/src/main/java/org/sinytra/adapter/patch/Patcher.java @@ -83,10 +83,15 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P MutableConfiguration configuration = MutableConfiguration.create(template); configuration.mergeFrom(mixin.properties()); + this.environment.auditTrail().prepareMethod(mixinContext); + PatchResult result = PatchResult.PASS; // << RUN EARLY PHASE for (MethodTransformer transformer : getTransformers(TxPhase.EARLY)) { + mixinContext.pushAudit(transformer); PatchResult txResult = transformer.apply(mixinContext, configuration); + mixinContext.popAudit(); + result = result.or(txResult); } @@ -99,7 +104,9 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P // << RUN LOADED PHASE for (MethodTransformer transformer : getTransformers(TxPhase.LOADED)) { + mixinContext.pushAudit(transformer); PatchResult txResult = transformer.apply(mixinContext, configuration); + mixinContext.popAudit(); result = result.or(txResult); } @@ -109,11 +116,10 @@ private PatchResult processMixin(ClassNode classNode, ClassTarget classTarget, P return PatchResult.PASS; } - // TODO Audit trail - this.environment.auditTrail().prepareMethod(mixinContext); - for (MethodTransformer transformer : getTransformers(TxPhase.VALIDATED)) { + mixinContext.pushAudit(transformer); PatchResult txResult = transformer.apply(mixinContext, configuration); + mixinContext.popAudit(); result = result.or(txResult); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java index 63188391..017898fc 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/mixin/InjectMixin.java @@ -1,6 +1,7 @@ package org.sinytra.adapter.patch.mixin; import org.objectweb.asm.Type; +import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.patch.config.ConfigurationTemplates; import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; @@ -18,8 +19,10 @@ import org.sinytra.adapter.patch.resolver.injection.ComparingInjectionPointResolver; import org.sinytra.adapter.patch.resolver.injection.InjectionPointResolver; import org.sinytra.adapter.patch.resolver.special.InjectorOrdinalResolver; +import org.sinytra.adapter.util.MethodQualifier; import java.util.List; +import java.util.Objects; import static org.sinytra.adapter.env.param.MethodParameters.ParamGroup.*; @@ -59,7 +62,7 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo return TxResult.SUCCESS; } - if (dirty.getTargetMethod().desc().equals(clean.getTargetMethod().desc())) { + if (sameTarget(recipe)) { dirty.inheritParameters(); } else { List cleanParams = clean.getParameters().getTypes(METHOD_PARAMS); @@ -88,4 +91,17 @@ public TxResult postProcess(MixinContext context, Configuration clean, MutableCo return TxResult.SUCCESS; } + + private boolean sameTarget(Recipe recipe) { + MethodQualifier cleanQ = recipe.clean().getTargetMethod(); + MethodQualifier dirtyQ = recipe.dirty().getTargetMethod(); + if (cleanQ != null && dirtyQ != null && Objects.equals(cleanQ.name(), dirtyQ.name()) && Objects.equals(cleanQ.desc(), dirtyQ.desc())) { + return true; + } + + TargetPair cleanTarget = recipe.getCleanTarget(); + TargetPair dirtyTarget = recipe.getDirtyTarget(); + return cleanTarget != null && dirtyTarget != null + && MethodQualifier.create(cleanTarget.methodNode()).matches(MethodQualifier.create(dirtyTarget.methodNode())); + } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java index 5587e26f..0bf7f018 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/DisableMixinProcessor.java @@ -11,10 +11,10 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe if (!dirty.shouldDelete()) { return TxResult.PASS; } - - // methodContext.recordAudit(this, "Remove mixin method"); + + context.recordCtxAudit("Remove mixin method"); context.patchContext().postApply(() -> context.classNode().methods.remove(context.methodNode())); - + return TxResult.FINALIZE; } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java index 07541494..e499ac39 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/MixinTypeProcessor.java @@ -22,7 +22,7 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe AnnotationNode methodAnn = methodNode.visibleAnnotations.get(i); if (methodAnn == annotation.unwrap()) { methodAnn.desc = dirty.getMixinType(); -// methodContext.recordAudit(this, "Modify type to %s", this.replacementDesc); + context.recordCtxAudit("Modify type to %s", methodAnn.desc); return TxResult.SUCCESS; } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java index 5c3b1797..00627419 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/ParametersProcessor.java @@ -24,6 +24,8 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe MethodParameters cleanParams = recipe.clean().getParameters(); MethodParameters dirtyParams = dirty.getParameters(); if (dirtyParams == null) return TxResult.FAIL; + if (cleanParams.merge().equals(dirtyParams.merge())) + return TxResult.PASS; // Apply mappings of params that will be removed in dirty Map> oldVarMap = Parameters.gatherVarMappings(context.methodNode(), cleanParams.merge(), dirtyParams.merge(), dirtyParams.getMapping()); diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java index f1cf63c7..431ea34b 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/PropertyProcessor.java @@ -28,6 +28,9 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe ACCEPTED_KEYS.forEach(k -> dirty.getProperty(k) .ifPresent(v -> subConfig.setProperty((PropertyKey) k, v))); + subConfig.getProperties().forEach((k, v) -> + context.recordCtxAudit("Set property '%s' to: %s", k.name(), v)); + // Apply new props subConfig.apply(handle); diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java index 8b7b55c7..c77a3739 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/StaticAccessProcessor.java @@ -27,14 +27,14 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe boolean actuallyStatic = MethodHelper.isStatic(context.methodNode()); // Add static if (!actuallyStatic && !cleanStatic && dirtyStatic) { - // context.recordAudit(this, "Adding access modifier %s", change.modifier); + context.recordCtxAudit("Made method static"); method.access |= Opcodes.ACC_STATIC; return TxResult.SUCCESS; } // Remove static else if (actuallyStatic && cleanStatic && !dirtyStatic) { - // context.recordAudit(this, "Removing access modifier %s", change.modifier); + context.recordCtxAudit("Made method non-static"); method.access &= ~Opcodes.ACC_STATIC; LocalVariableNode firstParam = method.localVariables.stream().filter(lvn -> lvn.index == 0) diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java index 36902860..a1163279 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/ExtractMixinProcessor.java @@ -38,9 +38,7 @@ public TxResult process(MixinContext context, Configuration dirty, Recipe recipe result = MirrorableExtractMixin.apply(context, recipe, dirty.getTargetClass(), minsn); } - if (result == PatchResult.PASS) return TxResult.FAIL; - - return TxResult.SUCCESS; + return result == PatchResult.PASS ? TxResult.FAIL : TxResult.SUCCESS; } // TODO Prioritize mirroring over extraction, remove locals recreation @@ -79,9 +77,8 @@ public static PatchResult apply(String targetClassName, MixinContext context, Re result = result.or(recreateLocalVariables(methodNode, context, recipe, generatedTarget)); } - // methodContext.recordAudit(this, "Extract mixin to target %s", targetClassName); + context.recordCtxAudit("Extract mixin to target %s", targetClassName); // Remove original method - // methodContext.recordAudit(this, "Remove original method"); context.patchContext().postApply(() -> classNode.methods.removeAll(candidates.methods)); return result.or(PatchResult.APPLY); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java index 0b22733a..5eccb788 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/extract/MirrorableExtractMixin.java @@ -95,6 +95,8 @@ public static PatchResult apply(MixinContext context, Recipe recipe, String dest gen.returnValue(); gen.newLabel(); gen.endMethod(); + + context.recordCtxAudit("Extract (mirror) mixin to target %s", destinationClass); return PatchResult.APPLY; } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java index b8a0bf69..2f74b8a1 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java @@ -85,7 +85,7 @@ private static boolean upgradeOriginalCall(MixinContext context, Configuration d .mapToObj(i -> { Parameter param = params.get(i); int index = lookup.getByParameterOrdinal(i).index; - return WrapOpOriginalCall.CallArg.create(i, List.of(AdapterUtil.loadType(param.getType(), index))); + return WrapOpOriginalCall.CallArg.create(i, List.of(AdapterUtil.loadType(param.type(), index))); }) .toList(); WrapOpOriginalCall reconstruct = new WrapOpOriginalCall(args); diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java index 1dd3f089..3663923c 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/CompoundResolver.java @@ -45,7 +45,9 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { } for (SubResolver subResolver : this.subResolvers) { + context.pushAudit(subResolver); Configuration result = subResolver.resolve(context, recipe); + context.popAudit(); if (result != null) { return ResolutionResult.success(result); } diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java index 211b749c..85a90292 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/InjectorOrdinalResolver.java @@ -139,7 +139,7 @@ public Configuration apply(MixinContext mixinContext, TargetPair cleanTarget, Ta Optional updatedValue = this.handler.apply(mixinContext, cleanTarget, dirtyTarget, this.context); if (updatedValue.isPresent()) { U value = updatedValue.get(); -// methodContext.recordAudit(transform, "Update injection point ordinal from %s to %s", this.context, value); + mixinContext.recordCtxAudit("Update injection point ordinal from %s to %s", this.context, value); return this.applicator.apply(value); } return null; diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java index 7f0215a0..e8dab03e 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/special/ModifyVarAtReturnResolver.java @@ -15,6 +15,7 @@ import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.env.ctx.TargetPair; import org.sinytra.adapter.env.MockMixinRuntime; +import org.sinytra.adapter.util.MethodQualifier; import org.spongepowered.asm.mixin.injection.modify.LocalVariableDiscriminator; import org.spongepowered.asm.mixin.injection.struct.InjectionInfo; import org.spongepowered.asm.mixin.injection.struct.Target; @@ -114,9 +115,8 @@ public ResolutionResult resolve(MixinContext context, Recipe recipe) { .inheritReturnType() .setProperty(MixinKeys.INDEX, i); - // TODO Audit -// String qualifier = MethodQualifier.create(dirtyMinsn).asDescriptor(); -// context.legacy().recordAudit(this, "Redirect RETURN variable modifier to parameter %s of method call to %s", i, qualifier); + String qualifier = MethodQualifier.create(dirtyMinsn).asDescriptor(); + context.recordCtxAudit("Redirect RETURN variable modifier to parameter %s of method call to %s", i, qualifier); return ResolutionResult.replace(config); } } diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java index 89bded2f..e45baa63 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitMethodCancellationHelper.java @@ -49,7 +49,7 @@ public static void handle(MixinContext context, Recipe recipe, MethodNode newTar generateCancellerMethod(generatedTarget, trackerField, originalClassTarget, invocations.get(i), context, i == invocations.size() - 1); } -// context.recordAudit(transform, "Generate cancellation handler mixin"); + context.recordCtxAudit("Generate cancellation handler mixin"); } private static void generateCancellerMethod(ClassNode generatedTarget, FieldNode trackerField, ClassNode originalClassTarget, MethodNode newTarget, MixinContext context, boolean reset) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java index 62f03662..4f927cb8 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/SplitTargetMethodSubResolver.java @@ -37,7 +37,7 @@ public Configuration resolve(MixinContext context, Recipe recipe) { if (candidates.size() == 1) { MethodNode method = candidates.getFirst().method(); -// methodContext.recordAudit(this, "Adjusting split method target to %s", newTarget); + context.recordCtxAudit("Adjusting split method target to %s", MethodQualifier.create(method).asDescriptor()); // TODO Move to processor if (recipe.clean().isCancellable()) { diff --git a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java index 6ee518a4..b72b6e96 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java +++ b/core/src/main/java/org/sinytra/adapter/patch/resolver/target/TargetMethodSubResolvers.java @@ -89,7 +89,10 @@ private static Configuration resolveReplacementCandidate(MixinContext context, R .sorted(Comparator.comparingInt(m -> Parameters.getParameterTypes(m.desc).size()).reversed()) .>flatMap(m -> { Configuration dirtyCopy = recipe.dirty().copy().setTargetMethod(m); - return resolver.resolve(context, recipe.withDirtyConfig(dirtyCopy)) + context.pushAudit(resolver); + Resolver.ResolutionResult result = resolver.resolve(context, recipe.withDirtyConfig(dirtyCopy)); + context.popAudit(); + return result .maybePatch() .stream() .map(c -> Pair.of(m, c.copyClean().setTargetMethod(m))); diff --git a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java index c919545d..ab5ce74b 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/PipelineMethodTransformer.java @@ -88,7 +88,9 @@ private PatchResult execute(MixinContext context, Configuration config) { // 2. Run Resolvers resolvers.freeze(); for (Resolver resolver : resolvers.getAll()) { + context.pushAudit(resolver); Resolver.ResolutionResult res = resolver.resolve(context, recipe); + context.popAudit(); Objects.requireNonNull(res, "BUG: Received null from resolver " + resolver.getClass()); if (res.type() == Resolver.ResultType.SUCCESS || res.type() == Resolver.ResultType.REPLACE) { @@ -126,7 +128,9 @@ private PatchResult execute(MixinContext context, Configuration config) { // 4. Run Processors processors.freeze(); for (Processor processor : processors.getAll()) { + context.pushAudit(processor); TxResult res = processor.process(context, dirtyConfig, recipe); + context.popAudit(); if (res == TxResult.FINALIZE) { break; } diff --git a/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java b/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java index 7ab469bc..903a0e0d 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java +++ b/core/src/main/java/org/sinytra/adapter/transform/param/TransformParameters.java @@ -32,17 +32,18 @@ public PatchResult apply(MixinContext context) { } if (result != PatchResult.PASS) { - updateDescription(methodNode, newParameterTypes); + updateDescription(context, methodNode, newParameterTypes); } return result; } - private void updateDescription(MethodNode methodNode, List parameters) { + private void updateDescription(MixinContext context, MethodNode methodNode, List parameters) { Type returnType = Type.getReturnType(methodNode.desc); - // recordAudit(transform, "Change descriptor to %s", newDesc); methodNode.desc = Type.getMethodDescriptor(returnType, parameters.toArray(Type[]::new)); methodNode.signature = null; + + context.recordCtxAudit("Change descriptor to %s", methodNode.desc); } private int calculateOffset(MixinContext context) { diff --git a/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java b/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java index 696b5f1f..017020a1 100644 --- a/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java +++ b/core/src/main/java/org/sinytra/adapter/transform/preprocess/LocalCaptureUpgradeTransformer.java @@ -58,10 +58,9 @@ public PatchResult apply(MixinContext context, Configuration config) { for (int i = start; i < args.length; i++) { methodNode.visitParameterAnnotation(i, MixinAnnotations.LOCAL, false); } - - AuditTrail auditTrail = context.environment().auditTrail(); -// auditTrail.recordAudit(this, methodContext, "Upgrade captured locals"); - auditTrail.recordResult(context, config, AuditTrail.Match.FULL); + + context.recordCtxAudit("Upgrade captured locals"); + context.environment().auditTrail().recordResult(context, config, AuditTrail.Match.FULL); return result; } } From 99f05e5b0c21d89055d2061880c9e4d2daf0dcac Mon Sep 17 00:00:00 2001 From: Su5eD Date: Tue, 3 Feb 2026 16:56:24 +0100 Subject: [PATCH 25/27] Box types in wrap op calls --- .../wrapop/WrapOpParamsProcessor.java | 14 +++++++-- .../org/sinytra/adapter/util/AdapterUtil.java | 30 +++++++++++++++++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java index 2f74b8a1..c6527ee0 100644 --- a/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java +++ b/core/src/main/java/org/sinytra/adapter/patch/processor/wrapop/WrapOpParamsProcessor.java @@ -4,6 +4,8 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.env.ctx.MixinContext; import org.sinytra.adapter.env.param.MethodParameters; import org.sinytra.adapter.env.param.Parameter; @@ -11,8 +13,6 @@ import org.sinytra.adapter.patch.TxResult; import org.sinytra.adapter.patch.config.Configuration; import org.sinytra.adapter.patch.processor.Processor; -import org.sinytra.adapter.analysis.locals.LocalVariableLookup; -import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; import org.sinytra.adapter.util.AdapterUtil; import org.sinytra.adapter.util.MethodQualifier; @@ -85,7 +85,15 @@ private static boolean upgradeOriginalCall(MixinContext context, Configuration d .mapToObj(i -> { Parameter param = params.get(i); int index = lookup.getByParameterOrdinal(i).index; - return WrapOpOriginalCall.CallArg.create(i, List.of(AdapterUtil.loadType(param.type(), index))); + Type type = param.type(); + + List loadInsns = new ArrayList<>(); + loadInsns.add(AdapterUtil.loadType(type, index)); + if (type.getSort() != Type.OBJECT) { + loadInsns.add(AdapterUtil.box(type)); + } + + return WrapOpOriginalCall.CallArg.create(i, loadInsns); }) .toList(); WrapOpOriginalCall reconstruct = new WrapOpOriginalCall(args); diff --git a/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java index 447a6adc..1553975a 100644 --- a/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java +++ b/core/src/main/java/org/sinytra/adapter/util/AdapterUtil.java @@ -207,7 +207,7 @@ public static CapturedLocals getCapturedLocals(MixinContext context, Recipe reci TargetPair target = recipe.getDirtyTarget(); if (target == null) return null; - return getCapturedLocals(context, target); + return getCapturedLocals(context, target); } // TODO Better way? @@ -221,7 +221,7 @@ public static CapturedLocals getCapturedLocals(MixinContext context, TargetPair LOGGER.debug("Missing CI or CIR argument in injector of type {}", context.methodAnnotation().getDesc()); return null; } - + List ignored = getAnnotatedParameters(methodNode, params, MixinAnnotations.SHARE, (node, type) -> type); Type[] availableParams = Stream.of(params).filter(t -> !ignored.contains(t)).toArray(Type[]::new); @@ -343,6 +343,32 @@ public static AbstractInsnNode getSingleInsn(List values, return getSingleInsn(value); } + public static MethodInsnNode box(Type primitive) { + Type boxed = boxedType(primitive); + return new MethodInsnNode( + Opcodes.INVOKESTATIC, + boxed.getInternalName(), + "valueOf", + Type.getMethodDescriptor(boxed, primitive), + false + ); + } + + private static Type boxedType(Type type) { + return switch (type.getSort()) { + case Type.BOOLEAN -> Type.getObjectType("java/lang/Boolean"); + case Type.BYTE -> Type.getObjectType("java/lang/Byte"); + case Type.CHAR -> Type.getObjectType("java/lang/Character"); + case Type.SHORT -> Type.getObjectType("java/lang/Short"); + case Type.INT -> Type.getObjectType("java/lang/Integer"); + case Type.FLOAT -> Type.getObjectType("java/lang/Float"); + case Type.LONG -> Type.getObjectType("java/lang/Long"); + case Type.DOUBLE -> Type.getObjectType("java/lang/Double"); + case Type.VOID -> Type.getObjectType("java/lang/Void"); + default -> throw new IllegalStateException("Not a primitive type: " + type); + }; + } + private AdapterUtil() { } } From e8bb03b0c8e8f25faf127f253d2e4122eaeda168 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Tue, 3 Feb 2026 17:12:12 +0100 Subject: [PATCH 26/27] Add Combatify test from #6 Co-authored-by: Alexandra-Myers --- .../test/mixin/DynamicMixinPatchTest.java | 9 +++++++ .../adapter/test/mixin/LivingEntityMixin.java | 27 +++++++++++++++++++ 2 files changed, 36 insertions(+) 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 38192547..5acb2752 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 @@ -253,6 +253,15 @@ void testUpdatedInjectionPointModifyExprVal() throws Exception { ); } + @Test + void testUpdatedInjectionPointModifyExprValConst() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mixin/FarmLandBlockMixin", + "changeIFrames", + assertInjectionPoint() + ); + } + @Test void testSplitMethodInjectionTarget() throws Exception { assertSameCode( diff --git a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java index 97d8df9e..11b29151 100644 --- a/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java +++ b/test/src/testClasses/java/org/sinytra/adapter/test/mixin/LivingEntityMixin.java @@ -1,5 +1,8 @@ package org.sinytra.adapter.test.mixin; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.LivingEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; @@ -74,4 +77,28 @@ public void testFrostWalkerExpected(CallbackInfo ci) { private void ourUniqueMethod() { // Noop } + + // https://github.com/Alexandra-Myers/Combatify/blob/1.21.1/src/main/java/net/atlas/combatify/mixin/InvulnerabilityMixin.java#L16 + @ModifyExpressionValue( + method = "hurt", + at = @At( + value = "CONSTANT", + args = "intValue=20", + ordinal = 0 + ) + ) + public int changeIFrames(int original, @Local(ordinal = 0, argsOnly = true) final DamageSource source, @Local(ordinal = 0, argsOnly = true) final float amount) { + return original; + } + + @ModifyExpressionValue( + method = "hurt", + at = @At( + value = "INVOKE", + target = "Lnet/neoforged/neoforge/common/damagesource/DamageContainer;getPostAttackInvulnerabilityTicks()I" + ) + ) + public int changeIFramesExpected(int original, @Local(ordinal = 0, argsOnly = true) final DamageSource source, @Local(ordinal = 0, argsOnly = true) final float amount) { + return original; + } } From 888b8eea9b49c7ed9dd4528d52bca41b660fc574 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Tue, 3 Feb 2026 17:52:05 +0100 Subject: [PATCH 27/27] Disable this test in CI --- .../adapter/patch/test/mixin/DynamicMixinPatchTest.java | 3 +++ 1 file changed, 3 insertions(+) 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 5acb2752..854cd462 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 @@ -4,6 +4,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; import org.objectweb.asm.tree.ClassNode; import org.sinytra.adapter.env.ctx.PatchEnvironment; import org.sinytra.adapter.env.ctx.RefmapHolder; @@ -445,7 +446,9 @@ void testModifiedVariableIndex() throws Exception { ); } + // Disabled in CI as the resulting ordinal is the same when decomp/recomp is disabled @Test + @DisabledIfEnvironmentVariable(named = "CI", matches = "true") void testModifiedReturnIndex() throws Exception { assertSameCode( "org/sinytra/adapter/test/mixin/pipeline/MaceItemMixin",