Rewrite constant parameter. A bit faster now. Can't tell if its right. Seems to compile.
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -31,7 +31,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.ow2.asm</groupId>
|
<groupId>org.ow2.asm</groupId>
|
||||||
<artifactId>asm-all</artifactId>
|
<artifactId>asm-debug-all</artifactId>
|
||||||
<version>5.0.4</version>
|
<version>5.0.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -10,17 +10,15 @@ import net.runelite.asm.attributes.code.Instruction;
|
|||||||
import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction;
|
import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction;
|
||||||
import net.runelite.asm.attributes.code.instruction.types.LVTInstruction;
|
import net.runelite.asm.attributes.code.instruction.types.LVTInstruction;
|
||||||
import net.runelite.asm.execution.Execution;
|
import net.runelite.asm.execution.Execution;
|
||||||
import net.runelite.asm.execution.Frame;
|
|
||||||
import net.runelite.asm.execution.InstructionContext;
|
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 net.runelite.asm.signature.Signature;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Map;
|
||||||
import net.runelite.asm.execution.StackContext;
|
import net.runelite.asm.execution.StackContext;
|
||||||
import net.runelite.asm.signature.util.VirtualMethods;
|
import net.runelite.asm.signature.util.VirtualMethods;
|
||||||
|
|
||||||
@@ -28,7 +26,57 @@ import org.apache.commons.collections4.CollectionUtils;
|
|||||||
|
|
||||||
public class UnusedParameters implements Deobfuscator
|
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;
|
int offset = method.isStatic() ? 0 : 1;
|
||||||
Signature signature = method.getNameAndType().getDescriptor();
|
Signature signature = method.getNameAndType().getDescriptor();
|
||||||
@@ -46,19 +94,18 @@ public class UnusedParameters implements Deobfuscator
|
|||||||
return unusedParams;
|
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()];
|
// get lvt index for parameter
|
||||||
for (int variableIndex = 0, lvtIndex = offset;
|
int lvtIndex = offset;
|
||||||
variableIndex < signature.size();
|
for (int variableIndex = 0;
|
||||||
lvtIndex += signature.getTypeOfArg(variableIndex++).getSlots())
|
variableIndex < parameter;
|
||||||
{
|
lvtIndex += signature.getTypeOfArg(variableIndex++).getSlots());
|
||||||
i[variableIndex] = lvtIndex;
|
return lvtIndex;
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<Integer> findUnusedParameters(Collection<Method> methods)
|
public Collection<Integer> findUnusedParameters(Collection<Method> methods)
|
||||||
{
|
{
|
||||||
Collection<Integer> list = null;
|
Collection<Integer> list = null;
|
||||||
|
|
||||||
@@ -72,82 +119,56 @@ public class UnusedParameters implements Deobfuscator
|
|||||||
list = CollectionUtils.intersection(list, p);
|
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 (ClassFile cf : group.getClasses())
|
||||||
|
for (Method m : cf.getMethods().getMethods())
|
||||||
|
{
|
||||||
|
Code c = m.getCode();
|
||||||
|
|
||||||
for (Frame f : execution.processedFrames)
|
if (c == null)
|
||||||
for (InstructionContext ins : f.getInstructions())
|
continue;
|
||||||
if (!ins.getInvokes().isEmpty() && methods.containsAll(ins.getInvokes()))
|
|
||||||
|
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
|
if (!(i instanceof InvokeInstruction))
|
||||||
|
|
||||||
StackContext sctx = ins.getPops().get(pops);
|
|
||||||
if (sctx.getPushed().getInstruction().getInstructions() == null)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ins.removeStack(pops); // remove parameter from stack
|
InvokeInstruction ii = (InvokeInstruction) i;
|
||||||
|
|
||||||
if (done.contains(ins.getInstruction()))
|
if (!ii.getMethods().containsAll(methods))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
InvokeInstruction iins = (InvokeInstruction) ins.getInstruction();
|
ii.removeParameter(paramIndex); // remove parameter from instruction
|
||||||
iins.removeParameter(paramIndex); // remove parameter from instruction
|
|
||||||
|
|
||||||
done.add(ins.getInstruction());
|
Collection<InstructionContext> ics = execution.getInstructonContexts(i);
|
||||||
}
|
if (ics != null)
|
||||||
|
|
||||||
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())
|
|
||||||
{
|
{
|
||||||
if (i instanceof InvokeInstruction)
|
InstructionContext ins = ics.toArray(new InstructionContext[0])[0];
|
||||||
{
|
|
||||||
InvokeInstruction ii = (InvokeInstruction) i;
|
|
||||||
PoolEntry pool = ii.getMethod();
|
|
||||||
|
|
||||||
if (pool instanceof net.runelite.asm.pool.Method)
|
int pops = signature.size() - paramIndex - 1; // index from top of stack of parameter. 0 is the last parameter
|
||||||
{
|
|
||||||
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))
|
StackContext sctx = ins.getPops().get(pops);
|
||||||
{
|
if (sctx.getPushed().getInstruction().getInstructions() == null)
|
||||||
// for some reason this wasn't removed above?
|
continue;
|
||||||
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))
|
ins.removeStack(pops); // remove parameter from stack
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (Method method : methods)
|
for (Method method : methods)
|
||||||
if (method.getCode() != null)
|
if (method.getCode() != null)
|
||||||
// adjust lvt indexes to get rid of idx in the method
|
// 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)
|
if (ins instanceof LVTInstruction)
|
||||||
{
|
{
|
||||||
@@ -160,8 +181,9 @@ public class UnusedParameters implements Deobfuscator
|
|||||||
if (i > lvtIndex)
|
if (i > lvtIndex)
|
||||||
{
|
{
|
||||||
assert i > 0;
|
assert i > 0;
|
||||||
|
assert i >= lvtIndex + slots;
|
||||||
|
|
||||||
Instruction newIns = lins.setVariableIndex(--i);
|
Instruction newIns = lins.setVariableIndex(i - slots);
|
||||||
assert ins == newIns;
|
assert ins == newIns;
|
||||||
// this doesn't work because we'd have to reexecute or the above Frames would be messing with these instructions
|
// this doesn't work because we'd have to reexecute or the above Frames would be messing with these instructions
|
||||||
//if (newIns != ins)
|
//if (newIns != ins)
|
||||||
@@ -174,63 +196,13 @@ public class UnusedParameters implements Deobfuscator
|
|||||||
method.arguments.remove(paramIndex);
|
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;
|
private int count;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ClassGroup group)
|
public void run(ClassGroup group)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int pnum = 1;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
group.buildClassGraph();
|
group.buildClassGraph();
|
||||||
@@ -239,7 +211,9 @@ public class UnusedParameters implements Deobfuscator
|
|||||||
execution.populateInitialMethods();
|
execution.populateInitialMethods();
|
||||||
execution.run();
|
execution.run();
|
||||||
|
|
||||||
i = checkParametersOnce(execution, group);
|
this.buildUnused(group);
|
||||||
|
i = this.processUnused(execution, group);
|
||||||
|
System.out.println("PASS " + pnum++ + " " + i);
|
||||||
|
|
||||||
count += i;
|
count += i;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package net.runelite.deob.deobfuscators;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import net.runelite.asm.ClassGroup;
|
import net.runelite.asm.ClassGroup;
|
||||||
|
import net.runelite.asm.Method;
|
||||||
|
import net.runelite.asm.signature.util.VirtualMethods;
|
||||||
import net.runelite.deob.util.JarUtil;
|
import net.runelite.deob.util.JarUtil;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@@ -35,7 +38,34 @@ public class UnusedParametersTest
|
|||||||
@Test
|
@Test
|
||||||
public void testRun()
|
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();
|
UnusedParameters cp = new UnusedParameters();
|
||||||
cp.run(group);
|
cp.run(group);
|
||||||
|
cp = null;
|
||||||
|
System.gc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user