diff --git a/src/main/java/info/sigterm/deob/Deob.java b/src/main/java/info/sigterm/deob/Deob.java index 681b95ba04..a63ddb1401 100644 --- a/src/main/java/info/sigterm/deob/Deob.java +++ b/src/main/java/info/sigterm/deob/Deob.java @@ -8,6 +8,9 @@ import info.sigterm.deob.attributes.Code; import info.sigterm.deob.attributes.code.Block; import info.sigterm.deob.attributes.code.Instruction; import info.sigterm.deob.attributes.code.Instructions; +import info.sigterm.deob.attributes.code.instructions.Goto; +import info.sigterm.deob.attributes.code.instructions.GotoW; +import info.sigterm.deob.attributes.code.instructions.Return; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -53,6 +56,7 @@ public class Deob Execution e = execute(group); checkParameters(e, group); + checkBlockGraphJump(group); JarOutputStream jout = new JarOutputStream(new FileOutputStream(args[1]), new Manifest()); @@ -165,6 +169,97 @@ public class Deob System.out.println("Removed " + i + " unused blocks"); } + private static int checkBlockGraphOnce(ClassGroup group) + { + int count = 0; + for (ClassFile cf : group.getClasses()) + { + for (Method m : new ArrayList<>(cf.getMethods().getMethods())) + { + if (m.getCode() == null) + continue; + + Instructions ins = m.getCode().getInstructions(); + ins.buildBlocks(); + ins.buildJumpGraph(); + List blocks = ins.getBlocks(); + for (int i = 0; i < blocks.size(); ++i) + { + Block block = blocks.get(i); + Block prev = i > 0 ? blocks.get(i - 1) : null; + + // only one thing jumps here + if (block.begin.from.size() == 1 && prev != null && prev.end.isTerminal()) + { + Instruction from = block.begin.from.get(0); // this instruction jumps to block + + if (from.block == block) + continue; + + if (from instanceof Goto || from instanceof GotoW) + { + ++count; + + List ilist = ins.getInstructions(); + + // remove instructions + for (Instruction in : block.instructions) + ilist.remove(in); + + int index = ilist.indexOf(from); + + assert from.block != block; + from.block = null; + + // move instructions which jump here to jump to block.begin + for (Instruction in : from.from) + { + assert in.jump.contains(from); + assert !in.jump.contains(block.begin); + + in.jump.remove(from); + + in.jump.add(block.begin); + block.begin.from.add(in); + } + from.from.clear(); + + // .replace ins + for (Instruction in : ilist) + in.replace(from, block.begin); + + for (info.sigterm.deob.attributes.code.Exception e : m.getCode().getExceptions().getExceptions()) + e.replace(from, block.begin); + + ins.remove(from); // remove jump + + // insert instructions from block where jump was + for (Instruction in : block.instructions) + ilist.add(index++, in); + } + } + } + } + } + return count; + } + + private static void checkBlockGraphJump(ClassGroup g) + { + int count = 0; + int passes = 0; + int i; + do + { + i = checkBlockGraphOnce(g); + count += i; + ++passes; + } + while (i > 0); + + System.out.println("Inlined " + count + " jumps in " + passes + " passes"); + } + private static int[] checkParametersOnce(Execution execution, ClassGroup group) { // removing parameters shifts the others around which is annoying. diff --git a/src/main/java/info/sigterm/deob/attributes/code/Instructions.java b/src/main/java/info/sigterm/deob/attributes/code/Instructions.java index 75ae825a1f..c4c77ffa08 100644 --- a/src/main/java/info/sigterm/deob/attributes/code/Instructions.java +++ b/src/main/java/info/sigterm/deob/attributes/code/Instructions.java @@ -86,6 +86,10 @@ public class Instructions public void buildBlocks() { + for (Instruction i : instructions) + i.block = null; + blocks.clear(); + Block current = null; for (Instruction i : instructions) { @@ -132,8 +136,14 @@ public class Instructions out.write(ba); } - private void buildJumpGraph() + public void buildJumpGraph() { + for (Instruction i : instructions) + { + i.jump.clear(); + i.from.clear(); + } + for (Instruction i : instructions) if (i instanceof JumpingInstruction) ((JumpingInstruction) i).buildJumpGraph();