Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d7fbe2f
Migrate DynFixSliceBoundary to pipeline
Su5eD Dec 26, 2025
e9c323e
Migrate DynFixAtVariableAssignStore to pipeline
Su5eD Dec 26, 2025
83cbec9
Migrate DynFixParameterTypeAdapter to pipeline
Su5eD Dec 27, 2025
36f174c
Dynamic property containers
Su5eD Dec 27, 2025
fe3ba03
Migrate dynamic fixers to transformation pipeline
Su5eD Jan 16, 2026
66bd633
New Patch pipeline and transformer itf
Su5eD Jan 23, 2026
3fbc9a0
Migrate away from MethodContext
Su5eD Jan 26, 2026
4216d6e
Rename definition to core
Su5eD Jan 26, 2026
c6758ba
Transformer pipeline phases
Su5eD Jan 27, 2026
5a7c0e5
Stable frame analysis
Su5eD Jan 27, 2026
74b3141
Patch method calls in redirect
Su5eD Jan 30, 2026
98324e8
Cleanup TODOs
Su5eD Jan 30, 2026
0e4d481
Fix frame analysis failing due to incorrect maxs
Su5eD Jan 30, 2026
5340a93
Fix plural key application
Su5eD Jan 30, 2026
f01372d
Injection point resolver for modified params
Su5eD Jan 31, 2026
2cdb897
Handle overloaded injection point targets
Su5eD Jan 31, 2026
0c58542
Cast replaced inherited parameters to expected type
Su5eD Jan 31, 2026
4281017
Remap parsed literal class targets
Su5eD Feb 1, 2026
35d884a
Parse mixins after running class transformers
Su5eD Feb 1, 2026
bf0ea6a
Improve overloaded target resolution
Su5eD Feb 1, 2026
f413db4
Fix LVLookup incorrect parameter ordinals
Su5eD Feb 1, 2026
1c09477
Fix Shared locals param capture
Su5eD Feb 1, 2026
777ec68
Use clear target in redirect when possible
Su5eD Feb 1, 2026
7f286e9
Pipeline Auditing
Su5eD Feb 2, 2026
99f05e5
Box types in wrap op calls
Su5eD Feb 3, 2026
e8bb03b
Add Combatify test from #6
Su5eD Feb 3, 2026
888b8ee
Disable this test in CI
Su5eD Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ build
eclipse
run

definition/logs
core/logs
test/logs
9 changes: 2 additions & 7 deletions definition/build.gradle.kts → core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ gradleutils.version {
}

version = gradleutils.version.toString() + "+$versionMc"
println("Definition version: $version")
println("Core version: $version")

java {
toolchain {
Expand All @@ -24,11 +24,6 @@ java {
withSourcesJar()
}

sourceSets.main {
java.srcDirs("src/next/java")
resources.srcDirs("src/next/resources")
}

repositories {
mavenCentral()
maven {
Expand All @@ -50,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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ gradle.beforeProject {
}
}

rootProject.name = "definition"
rootProject.name = "core"
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package org.sinytra.adapter.patch.analysis;
package org.sinytra.adapter.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 org.sinytra.adapter.util.provider.ClassLookup;

import java.util.*;

Expand All @@ -24,21 +22,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<String> getClassParents(String name) {
public Collection<String> getClassParents(String name) {
Collection<String> parents = this.parentCache.get(name);
if (parents == null) {
parents = computeClassParents(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package org.sinytra.adapter.patch.analysis;
package org.sinytra.adapter.analysis;

import com.mojang.datafixers.util.Pair;
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.MethodNode;
import org.sinytra.adapter.patch.api.MethodContext;
import org.sinytra.adapter.env.ctx.TargetPair;
import org.sinytra.adapter.patch.Recipe;

import java.util.*;
import java.util.stream.Stream;
Expand All @@ -16,8 +17,13 @@ public record ComparisonResult(List<List<AbstractInsnNode>> patchedLabels, List<
}

@Nullable
public static ComparisonResult findPatchedLabels(AbstractInsnNode cleanInjectionInsn, MethodContext methodContext) {
List<List<AbstractInsnNode>> 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<List<AbstractInsnNode>> cleanLabels = getLabelsInMethod(cleanTarget.methodNode());
List<List<AbstractInsnNode>> cleanLabelsOriginal = List.copyOf(cleanLabels);

List<List<AbstractInsnNode>> cleanMatchedLabels = cleanLabels.stream()
Expand All @@ -28,7 +34,7 @@ public static ComparisonResult findPatchedLabels(AbstractInsnNode cleanInjection
}
List<AbstractInsnNode> cleanLabel = cleanMatchedLabels.getFirst();

List<List<AbstractInsnNode>> dirtyLabels = getLabelsInMethod(methodContext.findDirtyInjectionTarget().methodNode());
List<List<AbstractInsnNode>> dirtyLabels = getLabelsInMethod(dirtyTarget.methodNode());
List<List<AbstractInsnNode>> dirtyLabelsOriginal = List.copyOf(dirtyLabels);

Map<List<AbstractInsnNode>, List<AbstractInsnNode>> matchedLabels = new LinkedHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -7,13 +7,14 @@
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import org.sinytra.adapter.patch.analysis.params.EnhancedParamsDiff;
import org.sinytra.adapter.patch.analysis.params.ParamsDiffSnapshot;
import org.sinytra.adapter.patch.api.MethodContext;
import org.sinytra.adapter.patch.api.MethodTransform;
import org.sinytra.adapter.patch.transformer.operation.param.TransformParameters;
import org.sinytra.adapter.patch.util.AdapterUtil;
import org.sinytra.adapter.patch.util.OpcodeUtil;
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;
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;
Expand All @@ -23,20 +24,19 @@

public final class LocalVarAnalyzer {

public record CapturedLocalsInfo(AdapterUtil.CapturedLocals capturedLocals, ParamsDiffSnapshot diff, List<Type> availableTypes) {}

public record CapturedLocalsInfo(AdapterUtil.CapturedLocals capturedLocals, ParamsDiffSnapshot diff, List<Type> 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<MethodContext.LocalVariable> available = methodContext.getTargetMethodLocals(capturedLocals.target());
if (available == null) {
return null;
}
List<Type> availableTypes = available.stream().map(MethodContext.LocalVariable::type).toList();
List<LocalVariable> available = context.methods().getTargetMethodLocals(capturedLocals.target());
if (available == null) return null;

List<Type> 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);
Expand All @@ -61,9 +61,10 @@ public static InsnList findInitializerInsns(MethodNode methodNode, int index) {
return insns;
}

public record CapturedLocalsUsage(LocalVariableLookup targetTable, Int2IntMap usageCount, Int2ObjectMap<InsnList> varInsnLists) {}
public record CapturedLocalsUsage(LocalVariableLookup targetTable, Int2IntMap usageCount, Int2ObjectMap<InsnList> varInsnLists) {
}

public record CapturedLocalsTransform(List<Integer> used, MethodTransform remover, List<LocalVariableNode> usedLocalNodes) {
public record CapturedLocalsTransform(List<Integer> used, TransformParameters remover, List<LocalVariableNode> usedLocalNodes) {
public CapturedLocalsUsage getUsage(AdapterUtil.CapturedLocals capturedLocals) {
LocalVariableLookup targetTable = new LocalVariableLookup(capturedLocals.target().methodNode());
Int2ObjectMap<InsnList> varInsnLists = new Int2ObjectOpenHashMap<>();
Expand Down Expand Up @@ -96,7 +97,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())
Expand Down Expand Up @@ -131,5 +132,6 @@ public static void findVariableInitializerInsns(MethodNode methodNode, boolean i
varInsnLists.put(index, insns);
}

private LocalVarAnalyzer() {}
private LocalVarAnalyzer() {
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
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;
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.*;

Expand All @@ -17,7 +17,7 @@ public class LocalVariableLookup {
private final Map<Type, List<LocalVariableNode>> 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);
Expand Down Expand Up @@ -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();
}
Expand Down
Loading