6 | Modifying Arguments

What is ModifyArg?

Consider the following method

private void aMethod() {
    System.out.println("No. 4561!");
    System.out.println("HElooo 25!");
    System.out.println("idk 356!");
    System.out.println("interesting 46!");
    System.out.println("Hi! 5!");
    System.out.println("Hello 1!");
    System.out.println("no? 456!");
    System.out.println("Bye 48!");
    System.out.println("ALLRIGHt 33!");
    System.out.println("lol 10!");
}

As you can clearly observe, it consists of a set print statements, which outputs 10 strings with no noticeable pattern.

So, what if I wanted to change the text "Hi! 5!" to "Hello world!"?

With our current knowledge all we could do is @Overwrite it, but this becomes very painful with larger method bodies with functions/variables that need @Shadow'ing (I will talk about shadowing later)

So what do we do?

May I introduce you to @ModifyArg; a neat function that allows us to modify the arguments of a method in a function

In the example provided, we can use @ModifyArg like so

@ModifyArg(method = "aMethod", at = @At(
            value = "INVOKE",
            target = "Ljava/io/PrintStream;println(Ljava/lang/String;)V",
            ordinal = 4),
           index = 0)
private String modifyOutput(String x) {
    return "Hello World!";
}

Since we've already covered most of what's going on inside that annotation, all we need to cover is the ordinal and the index .

  • ordinal = 4 (optional)

    • This allows you to set an offset of which println statement you actually want to modify, indexed by zero, in this case, it was set to 4, meaning that the 4th zero indexed println statement's arguments will be modified

  • index = 0

    • This is the last parameter that we have set, which isn't inside the @At statement, this allows us to select which argument in the function we want to modify (indexed by zero)

Lastly, the return statement, return "Hello World!", just returns what we want that argument to be

Modify Arg cont.

What happens if the argument we want to modify depends on all of the other arguments being passed in?

Say, instead of println accepting 1 argument (String), rather, it accepted 2 arguments, your message, and the number of times you want it to be printed

private void aMethod() {
    System.out.println("No. 4561!", 5);
    System.out.println("HElooo 25!", 3);
    System.out.println("idk 356!", 45);
    System.out.println("interesting 46!", 34);
    System.out.println("Hi! 5!", 34);
    System.out.println("Hello 1!", 42);
    System.out.println("no? 456!", 4);
    System.out.println("Bye 48!", 1);
    System.out.println("ALLRIGHt 33!", 99);
    System.out.println("lol 10!", 27);
}

In this example, once again, we want to change the text of "Hi! 5!" to "Hello world!", but this time we also want to add the number of times it will repeat to it (ie: "Hello World! (34)")

It's as simple as adding the extra arguments to the function, like shown below

@ModifyArg(method = "aMethod", at = @At(
            value = "INVOKE",
            target = "Ljava/io/PrintStream;println(Ljava/lang/String;I)V",
            ordinal = 4),
           index = 0)
private String modifyOutput(String x, int nTimesToRepeat) {
    return "Hello World! (" + nTimesToRepeat + ")";
}

ModifyArg vs Modify Args

While going through this tutorial, you might've noticed that there's another annotation called ModifyArgs instead of ModifyArg . So, what's the difference?

Well, using the former example where println has 2 arguments, a message and a number of times to print that message, we can modify multiple arguments like so

@ModifyArgs(method = "aMethod", at = @At(
            value = "INVOKE",
            target = "Ljava/io/PrintStream;println(Ljava/lang/String;I)V",
            ordinal = 4))
private void modifyOutput(Args args) {
    String x = args.get(0);
    int nTimesToRepeat = args.get(1);

    args.set(0, "Hello world! (" + nTimesToRepeat + ")");
    args.set(1, nTimesToRepeat + 20);
}

Args? What's that?

Args is a class provided by Mixin that provides 2 major methods

  • args.get(int index)

    • This allows you to retrieve one of the function's arguments be index

  • args.set(int index, T value)

    • This allows you to set an arguments value by index

An annotated example of ModifyArgs is shown below

String x = args.get(0); // Get the first argument, the string
int nTimesToRepeat = args.get(1); // Get the second argument, the number of times to repeat the message

args.set(0, "Hello world! (" + nTimesToRepeat + ")"); // Set the first argument to the string "Hello world! (n)", with n being the number of times to repeat
args.set(1, nTimesToRepeat + 20); // This takes the number of times to repeat, and adds the value 20 to it

Last updated

Was this helpful?