Skip to content

Commit

Permalink
Fix: Resolve @Redirects breaking @ModifyArgs.
Browse files Browse the repository at this point in the history
  • Loading branch information
LlamaLad7 committed Mar 1, 2024
1 parent a257aa1 commit b738ed2
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
import java.util.Arrays;
import java.util.List;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodInsnNode;
import org.spongepowered.asm.mixin.injection.InjectionPoint;
import org.spongepowered.asm.mixin.injection.InjectionPoint.RestrictTargetLevel;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.invoke.util.InvokeUtil;
import org.spongepowered.asm.mixin.injection.struct.InjectionInfo;
import org.spongepowered.asm.mixin.injection.struct.InjectionNodes.InjectionNode;
import org.spongepowered.asm.mixin.injection.struct.Target;
Expand Down Expand Up @@ -110,12 +110,8 @@ protected void inject(Target target, InjectionNode node) {
@Override
protected void injectAtInvoke(Target target, InjectionNode node) {
MethodInsnNode methodNode = (MethodInsnNode)node.getCurrentTarget();
Type[] originalArgs = Type.getArgumentTypes(((MethodInsnNode) node.getOriginalTarget()).desc);
Type[] currentArgs = Type.getArgumentTypes(methodNode.desc);
if (node.isReplaced() && node.hasDecoration(RedirectInjector.Meta.KEY) && methodNode.getOpcode() != Opcodes.INVOKESTATIC) {
// A redirect handler method for a virtual target will have an extra arg at the start that we don't care about.
currentArgs = Arrays.copyOfRange(currentArgs, 1, currentArgs.length);
}
Type[] originalArgs = InvokeUtil.getOriginalArgs(node);
Type[] currentArgs = InvokeUtil.getCurrentArgs(node);
int argIndex = this.findArgIndex(target, originalArgs);
InsnList insns = new InsnList();
Extension extraLocals = target.extendLocals();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@
import org.spongepowered.asm.mixin.injection.InjectionPoint.RestrictTargetLevel;
import org.spongepowered.asm.mixin.injection.ModifyArgs;
import org.spongepowered.asm.mixin.injection.invoke.arg.ArgsClassGenerator;
import org.spongepowered.asm.mixin.injection.invoke.util.InvokeUtil;
import org.spongepowered.asm.mixin.injection.struct.InjectionInfo;
import org.spongepowered.asm.mixin.injection.struct.InjectionNodes.InjectionNode;
import org.spongepowered.asm.mixin.injection.struct.Target;
import org.spongepowered.asm.mixin.injection.struct.Target.Extension;
import org.spongepowered.asm.mixin.injection.throwables.InvalidInjectionException;
import org.spongepowered.asm.util.Bytecode;

import java.util.Arrays;

/**
* A bytecode injector which allows a single argument of a chosen method call to
* be altered. For details see javadoc for {@link ModifyArgs @ModifyArgs}.
Expand Down Expand Up @@ -78,28 +81,33 @@ protected void inject(Target target, InjectionNode node) {
@Override
protected void injectAtInvoke(Target target, InjectionNode node) {
MethodInsnNode targetMethod = (MethodInsnNode)node.getCurrentTarget();

Type[] args = Type.getArgumentTypes(targetMethod.desc);
if (args.length == 0) {

Type[] originalArgs = InvokeUtil.getOriginalArgs(node);
Type[] currentArgs = InvokeUtil.getCurrentArgs(node);
if (originalArgs.length == 0) {
throw new InvalidInjectionException(this.info, "@ModifyArgs injector " + this + " targets a method invocation "
+ targetMethod.name + targetMethod.desc + " with no arguments!");
}

String clArgs = this.argsClassGenerator.getArgsClass(targetMethod.desc, this.info.getMixin().getMixin()).getName();

String originalDesc = Type.getMethodDescriptor(Type.VOID_TYPE, originalArgs);
String clArgs = this.argsClassGenerator.getArgsClass(originalDesc, this.info.getMixin().getMixin()).getName();
boolean withArgs = this.verifyTarget(target);

InsnList insns = new InsnList();
Extension extraStack = target.extendStack().add(1);

this.packArgs(insns, clArgs, targetMethod);


Type[] extraArgs = Arrays.copyOfRange(currentArgs, originalArgs.length, currentArgs.length);
int[] extraArgMap = this.storeArgs(target, extraArgs, insns, 0);
this.packArgs(insns, clArgs, originalDesc);

if (withArgs) {
extraStack.add(target.arguments);
Bytecode.loadArgs(target.arguments, insns, target.isStatic ? 0 : 1);
}

this.invokeHandler(insns);
this.unpackArgs(insns, clArgs, args);
this.unpackArgs(insns, clArgs, originalArgs);
this.pushArgs(extraArgs, insns, extraArgMap, 0, extraArgs.length);

extraStack.apply();
target.insns.insertBefore(targetMethod, insns);
Expand All @@ -121,8 +129,8 @@ private boolean verifyTarget(Target target) {
return false;
}

private void packArgs(InsnList insns, String clArgs, MethodInsnNode targetMethod) {
String factoryDesc = Bytecode.changeDescriptorReturnType(targetMethod.desc, "L" + clArgs + ";");
private void packArgs(InsnList insns, String clArgs, String targetDesc) {
String factoryDesc = Bytecode.changeDescriptorReturnType(targetDesc, "L" + clArgs + ";");
insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, clArgs, "of", factoryDesc, false));
insns.add(new InsnNode(Opcodes.DUP));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public class RedirectInjector extends InvokeInjector {
/**
* Meta decoration object for redirector target nodes
*/
class Meta {
public class Meta {

public static final String KEY = "redirector";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* This file is part of Mixin, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.spongepowered.asm.mixin.injection.invoke.util;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.MethodInsnNode;
import org.spongepowered.asm.mixin.injection.invoke.RedirectInjector;
import org.spongepowered.asm.mixin.injection.struct.InjectionNodes.InjectionNode;

import java.util.Arrays;

public class InvokeUtil {
public static Type[] getOriginalArgs(InjectionNode node) {
return Type.getArgumentTypes(((MethodInsnNode) node.getOriginalTarget()).desc);
}

public static Type[] getCurrentArgs(InjectionNode node) {
MethodInsnNode methodNode = (MethodInsnNode) node.getCurrentTarget();
Type[] currentArgs = Type.getArgumentTypes(methodNode.desc);
if (node.isReplaced() && node.hasDecoration(RedirectInjector.Meta.KEY) && methodNode.getOpcode() != Opcodes.INVOKESTATIC) {
// A redirect handler method for a virtual target will have an extra arg at the start that we don't care about.
return Arrays.copyOfRange(currentArgs, 1, currentArgs.length);
}
return currentArgs;
}
}

0 comments on commit b738ed2

Please sign in to comment.