Mixin icon indicating copy to clipboard operation
Mixin copied to clipboard

@Redirect on switch statements

Open Frontear opened this issue 6 years ago • 5 comments

Let's give an example class:

class SomeClass {
	public void something() {
		// ...
		switch (value) {
			case A:
				// ...
				break;
			case B:
			case C:
				b_and_c(value);
				break;
		}
	}

I want to be able to redirect this switch statement so that I can handle it my own way, or I guess, in other words, replace it with my own functionality, however I am having trouble with that. I tried something using JUMP Injection, which didn't really work

Mixin(SomeClass.class) class MixinSomeClass {
	@Redirect(method = "something", at = @At(value = "JUMP", target = "LSomeClass;something()V;", opcode = Opcodes.TABLESWITCH)) private void switch_redirect(Value value) {
     switch (value) {
          case A:
               b_c(value); // just an example
               break;
          case B:
          case C:
               //...
	}
}

As expected, the above fails, specifically because JumpInsnPoint doesn't actually support TABLESWITCH. All that being said, how can I redirect/replace this switch statement. Obviously, I could @Overwrite the whole method, but considering the size of it, it's not a very useful solution, I'd just need to shadow tons of fields and methods before I could even begin to work with it.

Frontear avatar Aug 18 '19 02:08 Frontear

There isn't a particularly straightforward way to entirely jump over a switch, however it would absolutely be possible to special-case redirect of LOOKUPSWITCH and TABLESWITCH so that a redirector could return the value being used for the switch itself, allowing deliberate redirection into the default case or a specific case. In the situation that the default is not supplied, this would provide a way to short-circuit the switch.

Coercion could potentially be used for switch-on-string and switch-on-enum as well but I'd have to look into that.

Mumfrey avatar Aug 19 '19 15:08 Mumfrey

I am not sure if I understood this correctly, but I am trying to replace the following:

private void call(int i) {
    switch (i) {
    case 65:
        System.out.println(65);
    }
}

With this:

private void call(int i) {
    switch (i) {
    case 70:
        System.out.println(65);
    }
}

This isn't currently possible, is it?

mainrs avatar Dec 05 '19 17:12 mainrs

Correct, that would need the solution to this issue.

However, if it's really that simple (or similar complexity) then you could potentially cheat using @ModifyVariable and just modify i to have the value 65 whenever it's 70 and have some other value when it isn't.

Mumfrey avatar Dec 05 '19 19:12 Mumfrey

Any resources on how to get started contributing? I have no experience with bytecode manipulation but would happily try to implement this. Maybe like a short todo overview/list or something I can follow? :)

mainrs avatar Dec 05 '19 22:12 mainrs

It's not really bytecode manipulation so much as it is ASM. If you understand that, you'd likely be able to get a working solution.

Frontear avatar Dec 06 '19 15:12 Frontear