I'm trying to prevent conditionals jumps from being useless for example by deleting that :
if(1 > 10) {
return;
}
So I decided to create a BasicInterpreter
to check if the frame of the jump is null
and if so remove it. And it's not null
so it doesn't detect it as useless.
Code which doesn't work :
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
if(frames[i] == null) {
System.out.println("This jump is useless");
}
}
}
}
Then I tried to get some values of stack to manually calculate but without any success (I found that but I cannot port the code to use it on jumps ASM Get exact value from stack frame):
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
// getStackSize() returns 2 so -> 0 and 1
frames[i].getStack(0); // this is probably 1
frames[i].getStack(1); // this is probably 10
// but it returns a BasicValue so I can't check if the code works or not (we cannot get values)
}
}
}
And the last thing I tried was to get the size of the instructions which are used by the jump to delete them (of course it doesn't detect if it's a useless code but I can at least delete it).
In fact I tried to create a method which returns a constant int so I can detect if getValue is called in the instructions of the jump (if I detect the invoke, I delete the instructions of the jump and the jump itself of course):
Example:
if(1 > getValue()) { //getValue() returns 10
return;
}
Code:
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
ArrayList<AbstractInsnNode> nodesR = new ArrayList<>();
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
ArrayList<AbstractInsnNode> toRemove = new ArrayList<>();
for (int ia = 1; ia < frames[i].getMaxStackSize() + 2; ia++) { // I started from 1 and added 2 to getMaxStackSize because I wasn't getting all the instructions
toRemove.add(mn.instructions.get(i - ia));
}
toRemove.add(mn.instructions.get(i)); // I add the jump to the list
for (AbstractInsnNode aaa : toRemove) {
if (aaa.getOpcode() == INVOKESTATIC) { // the invokestatic is getValue
for (AbstractInsnNode aaas : toRemove) {
nodesR.add(aaas);
}
break;
}
}
}
}
}
for (AbstractInsnNode aaas : nodesR) {
mn.instructions.remove(aaas);
}
} catch (AnalyzerException e) {
e.printStackTrace();
}
This code is probably horrible and not optimized but I tried a LOT of things without any success. The getMaxStackSize() doesn't return a number which is 100% correct (sometimes it doesn't take additions etc so it deletes instructions such as labels etc...).
What I'm trying to do:
Parsing through a method and check if a conditional jump will always be false (so the code inside will never gets executed) then remove it. I tried two different way:
- Use a
BasicInterpreter
to check if this jump will get executed with constant values then try it to see if it will always be false - Check if the jump contains a certain method (for example
getValue()
which returns 10 and compare if it's less than 1) then remove it What I don't understand : - I think that there is frames in each instructions and that it contains the local variables table and the values that the frame is using – StackMap ? - ( for example if the instruction compare if an int is less than another it would return [II] right ?
- I don't know if I can use a
BasicInterpreter
to test if the two constant ints always return the same result - StackMap = the Stack ? or it's different like the StackMap is a part of the stack which contains the needed values for the instruction ?