diff --git a/pom.xml b/pom.xml
index cd9bc692a1..a867b47ec8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
org.ow2.asm
- asm-all
+ asm-debug-all
5.0.4
diff --git a/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java b/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java
index 12f129a3a3..0f36421924 100644
--- a/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java
+++ b/src/main/java/net/runelite/deob/deobfuscators/UnusedParameters.java
@@ -10,25 +10,73 @@ import net.runelite.asm.attributes.code.Instruction;
import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction;
import net.runelite.asm.attributes.code.instruction.types.LVTInstruction;
import net.runelite.asm.execution.Execution;
-import net.runelite.asm.execution.Frame;
import net.runelite.asm.execution.InstructionContext;
-import net.runelite.asm.pool.NameAndType;
-import net.runelite.asm.pool.PoolEntry;
import net.runelite.asm.signature.Signature;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
-import java.util.Set;
+import java.util.Map;
import net.runelite.asm.execution.StackContext;
import net.runelite.asm.signature.util.VirtualMethods;
import org.apache.commons.collections4.CollectionUtils;
public class UnusedParameters implements Deobfuscator
-{
- private List findUnusedParameters(Method method)
+{
+ private Map, Collection> unused = new HashMap<>();
+
+ private void buildUnused(ClassGroup group)
+ {
+ unused.clear();
+
+ for (ClassFile cf : group.getClasses())
+ for (Method m : cf.getMethods().getMethods())
+ {
+ if (!Deob.isObfuscated(m.getName()))
+ continue;
+
+ List ms = VirtualMethods.getVirutalMethods(m);
+ Collection u = this.findUnusedParameters(ms);
+ if (!u.isEmpty())
+ unused.put(ms, u);
+ }
+ }
+
+ private int processUnused(Execution execution, ClassGroup group)
+ {
+ int count = 0;
+
+ for (List m : unused.keySet())
+ {
+ Collection u = unused.get(m);
+
+ int offset = m.size() == 1 && m.get(0).isStatic() ? 0 : 1;
+
+ for (int unusedParameter : u)
+ {
+ Signature signature = m.get(0).getDescriptor();
+ //int[] lvtIndexes = getLvtIndexes(signature, offset);//XX reverse this
+ int lvtIndex = this.getLvtIndex(signature, offset, unusedParameter);
+ /* removing the parameter can't cause collisions on other (overloaded) methods because prior to this we rename
+ * all classes/fields/methods to have unique names.
+ */
+ System.out.println("Removing parameter " + unusedParameter + " at index " + lvtIndex + " from " + m);
+ removeParameter(group, m, signature, execution, unusedParameter, lvtIndex);
+ break;
+ }
+
+ ++count;
+
+ //break;
+ }
+
+ return count;
+ }
+
+ public List findUnusedParameters(Method method)
{
int offset = method.isStatic() ? 0 : 1;
Signature signature = method.getNameAndType().getDescriptor();
@@ -46,19 +94,18 @@ public class UnusedParameters implements Deobfuscator
return unusedParams;
}
- private int[] getLvtIndexes(Signature signature, int offset)
+ @SuppressWarnings("empty-statement")
+ private int getLvtIndex(Signature signature, int offset, int parameter)
{
- int[] i = new int[signature.size()];
- for (int variableIndex = 0, lvtIndex = offset;
- variableIndex < signature.size();
- lvtIndex += signature.getTypeOfArg(variableIndex++).getSlots())
- {
- i[variableIndex] = lvtIndex;
- }
- return i;
+ // get lvt index for parameter
+ int lvtIndex = offset;
+ for (int variableIndex = 0;
+ variableIndex < parameter;
+ lvtIndex += signature.getTypeOfArg(variableIndex++).getSlots());
+ return lvtIndex;
}
- private Collection findUnusedParameters(Collection methods)
+ public Collection findUnusedParameters(Collection methods)
{
Collection list = null;
@@ -72,82 +119,56 @@ public class UnusedParameters implements Deobfuscator
list = CollectionUtils.intersection(list, p);
}
- return list;
+ List l = new ArrayList<>(list);
+ Collections.sort(l);
+ Collections.reverse(l);
+ return l;
}
- public void removeParameter(List methods, Signature signature, Execution execution, int paramIndex, int lvtIndex)
+ public void removeParameter(ClassGroup group, List methods, Signature signature, Execution execution, int paramIndex, int lvtIndex)
{
- Set done = new HashSet<>();
+ int slots = signature.getTypeOfArg(paramIndex).getSlots();
- assert signature.getTypeOfArg(paramIndex).getSlots() == 1;
-
- for (Frame f : execution.processedFrames)
- for (InstructionContext ins : f.getInstructions())
- if (!ins.getInvokes().isEmpty() && methods.containsAll(ins.getInvokes()))
+ for (ClassFile cf : group.getClasses())
+ for (Method m : cf.getMethods().getMethods())
+ {
+ Code c = m.getCode();
+
+ if (c == null)
+ continue;
+
+ for (Instruction i : new ArrayList<>(c.getInstructions().getInstructions()))
{
- int pops = signature.size() - paramIndex - 1; // index from top of stack of parameter. 0 is the last parameter
-
- StackContext sctx = ins.getPops().get(pops);
- if (sctx.getPushed().getInstruction().getInstructions() == null)
+ if (!(i instanceof InvokeInstruction))
continue;
- ins.removeStack(pops); // remove parameter from stack
+ InvokeInstruction ii = (InvokeInstruction) i;
- if (done.contains(ins.getInstruction()))
+ if (!ii.getMethods().containsAll(methods))
continue;
- InvokeInstruction iins = (InvokeInstruction) ins.getInstruction();
- iins.removeParameter(paramIndex); // remove parameter from instruction
+ ii.removeParameter(paramIndex); // remove parameter from instruction
- done.add(ins.getInstruction());
- }
-
- for (Method method : methods)
- // this double checks that all calls to this have been located
- for (ClassFile cf : method.getMethods().getClassFile().getGroup().getClasses())
- for (Method m : cf.getMethods().getMethods())
- {
- Code c = m.getCode();
- if (c == null)
- continue;
-
- for (Instruction i : c.getInstructions().getInstructions())
+ Collection ics = execution.getInstructonContexts(i);
+ if (ics != null)
{
- if (i instanceof InvokeInstruction)
- {
- InvokeInstruction ii = (InvokeInstruction) i;
- PoolEntry pool = ii.getMethod();
-
- if (pool instanceof net.runelite.asm.pool.Method)
- {
- net.runelite.asm.pool.Method pm = (net.runelite.asm.pool.Method) pool;
-
- if (pm.getClassEntry().getName().equals(method.getMethods().getClassFile().getName()) && pm.getNameAndType().equals(method.getNameAndType()) && !done.contains(i))
- {
- // for some reason this wasn't removed above?
- System.err.println("Method " + m.getName() + " in " + cf.getName() + " calls " + pm.getNameAndType().getName() + " in " + pm.getClassEntry().getName() + " at " + i.getPc() + ", but this instruction was not found during execution");
- //assert false;
- }
- }
- else if (pool instanceof net.runelite.asm.pool.InterfaceMethod)
- {
- net.runelite.asm.pool.InterfaceMethod pm = (net.runelite.asm.pool.InterfaceMethod) pool;
-
- if (pm.getClassEntry().getName().equals(method.getMethods().getClassFile().getName()) && pm.getNameAndType().equals(method.getNameAndType()) && !done.contains(i))
- {
- // for some reason this wasn't removed above?
- System.err.println("Method " + m.getName() + " in " + cf.getName() + " calls " + pm.getNameAndType().getName() + " in " + pm.getClassEntry().getName() + " at " + i.getPc() + ", but this instruction was not found during execution");
- //assert false;
- }
- }
- }
+ InstructionContext ins = ics.toArray(new InstructionContext[0])[0];
+
+ int pops = signature.size() - paramIndex - 1; // index from top of stack of parameter. 0 is the last parameter
+
+ StackContext sctx = ins.getPops().get(pops);
+ if (sctx.getPushed().getInstruction().getInstructions() == null)
+ continue;
+
+ ins.removeStack(pops); // remove parameter from stack
}
}
+ }
for (Method method : methods)
if (method.getCode() != null)
// adjust lvt indexes to get rid of idx in the method
- for (Instruction ins : new ArrayList<>(method.getCode().getInstructions().getInstructions()))
+ for (Instruction ins : method.getCode().getInstructions().getInstructions())
{
if (ins instanceof LVTInstruction)
{
@@ -160,8 +181,9 @@ public class UnusedParameters implements Deobfuscator
if (i > lvtIndex)
{
assert i > 0;
+ assert i >= lvtIndex + slots;
- Instruction newIns = lins.setVariableIndex(--i);
+ Instruction newIns = lins.setVariableIndex(i - slots);
assert ins == newIns;
// this doesn't work because we'd have to reexecute or the above Frames would be messing with these instructions
//if (newIns != ins)
@@ -173,57 +195,6 @@ public class UnusedParameters implements Deobfuscator
for (Method method : methods)
method.arguments.remove(paramIndex);
}
-
- private int checkParametersOnce(Execution execution, ClassGroup group)
- {
- // removing parameters shifts the others around which is annoying.
- // if more than one is unused, we'll just remove the one
- // and do the others on another pass
-
- Set done = new HashSet<>();
- int count = 0;
-
- for (ClassFile cf : group.getClasses())
- {
- for (Method m : cf.getMethods().getMethods())
- {
- if (done.contains(m) || !Deob.isObfuscated(m.getName()))
- continue;
-
- int offset = m.isStatic() ? 0 : 1;
- Signature signature = m.getNameAndType().getDescriptor();
-
- // for a parameter to be unused it must be unused on all methods that override it
-
- List methods = VirtualMethods.getVirutalMethods(m);
-
- Collection unusedParameters = findUnusedParameters(methods);
-
- if (unusedParameters.isEmpty())
- continue;
-
- int unusedParameter = (int) unusedParameters.toArray()[0];
- int[] lvtIndexes = getLvtIndexes(signature, offset);
-
- for (Method m2 : methods)
- {
- assert !done.contains(m2);
- done.add(m2);
- }
-
- /* removing the parameter can't cause collisions on other (overloaded) methods because prior to this we rename
- * all classes/fields/methods to have unique names.
- */
- System.out.println("Removing parameter " + unusedParameter + " from " + methods.get(0).getName());
- removeParameter(methods, signature, execution, unusedParameter, lvtIndexes[unusedParameter]);
-
- ++count;
-
- break;
- }
- }
- return count;
- }
private int count;
@@ -231,6 +202,7 @@ public class UnusedParameters implements Deobfuscator
public void run(ClassGroup group)
{
int i;
+ int pnum = 1;
do
{
group.buildClassGraph();
@@ -239,7 +211,9 @@ public class UnusedParameters implements Deobfuscator
execution.populateInitialMethods();
execution.run();
- i = checkParametersOnce(execution, group);
+ this.buildUnused(group);
+ i = this.processUnused(execution, group);
+ System.out.println("PASS " + pnum++ + " " + i);
count += i;
}
diff --git a/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java b/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java
index 2f9cbb5a58..8580775afe 100644
--- a/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java
+++ b/src/test/java/net/runelite/deob/deobfuscators/UnusedParametersTest.java
@@ -2,7 +2,10 @@ package net.runelite.deob.deobfuscators;
import java.io.File;
import java.io.IOException;
+import java.util.List;
import net.runelite.asm.ClassGroup;
+import net.runelite.asm.Method;
+import net.runelite.asm.signature.util.VirtualMethods;
import net.runelite.deob.util.JarUtil;
import org.junit.After;
import org.junit.Assert;
@@ -34,8 +37,35 @@ public class UnusedParametersTest
@Test
public void testRun()
- {
+ {
+ RenameUnique r = new RenameUnique();
+ r.run(group);
+ r = null;
+ System.gc();
+
+ RuntimeExceptions re = new RuntimeExceptions();
+ re.run(group);
+ re = null;
+ System.gc();
+
+ UnreachedCode uc = new UnreachedCode();
+ uc.run(group);
+ uc = null;
+ System.gc();
+
+ UnusedMethods um = new UnusedMethods();
+ um.run(group);
+ um = null;
+ System.gc();
+
+ IllegalStateExceptions ise = new IllegalStateExceptions();
+ ise.run(group);
+ ise = null;
+ System.gc();
+
UnusedParameters cp = new UnusedParameters();
cp.run(group);
+ cp = null;
+ System.gc();
}
}