Rewrite constant parameter. A bit faster now. Can't tell if its right. Seems to compile.

This commit is contained in:
Adam
2016-03-25 21:52:23 -04:00
parent 5ef0be50bf
commit 3444655f09
3 changed files with 134 additions and 130 deletions

View File

@@ -31,7 +31,7 @@
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<artifactId>asm-debug-all</artifactId>
<version>5.0.4</version>
</dependency>
<dependency>

View File

@@ -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<Integer> findUnusedParameters(Method method)
{
private Map<List<Method>, Collection<Integer>> 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<Method> ms = VirtualMethods.getVirutalMethods(m);
Collection<Integer> u = this.findUnusedParameters(ms);
if (!u.isEmpty())
unused.put(ms, u);
}
}
private int processUnused(Execution execution, ClassGroup group)
{
int count = 0;
for (List<Method> m : unused.keySet())
{
Collection<Integer> 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<Integer> 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<Integer> findUnusedParameters(Collection<Method> methods)
public Collection<Integer> findUnusedParameters(Collection<Method> methods)
{
Collection<Integer> list = null;
@@ -72,82 +119,56 @@ public class UnusedParameters implements Deobfuscator
list = CollectionUtils.intersection(list, p);
}
return list;
List<Integer> l = new ArrayList<>(list);
Collections.sort(l);
Collections.reverse(l);
return l;
}
public void removeParameter(List<Method> methods, Signature signature, Execution execution, int paramIndex, int lvtIndex)
public void removeParameter(ClassGroup group, List<Method> methods, Signature signature, Execution execution, int paramIndex, int lvtIndex)
{
Set<Instruction> 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<InstructionContext> 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<Method> 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<Method> methods = VirtualMethods.getVirutalMethods(m);
Collection<Integer> 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;
}

View File

@@ -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();
}
}