playing with less memory
This commit is contained in:
@@ -17,14 +17,14 @@ import org.apache.commons.collections4.map.MultiValueMap;
|
|||||||
public class Execution
|
public class Execution
|
||||||
{
|
{
|
||||||
private ClassGroup group;
|
private ClassGroup group;
|
||||||
public List<Frame> frames = new LinkedList<>(),
|
public List<Frame> frames = new LinkedList<>();
|
||||||
processedFrames = new LinkedList<>();
|
|
||||||
public Set<Method> methods = new HashSet<>(); // all methods
|
public Set<Method> methods = new HashSet<>(); // all methods
|
||||||
public Set<Instruction> executed = new HashSet<>(); // executed instructions
|
public Set<Instruction> executed = new HashSet<>(); // executed instructions
|
||||||
private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>();
|
private MultiValueMap<WeakInstructionContext, Method> invokes = new MultiValueMap<>();
|
||||||
public MultiValueMap<Instruction, InstructionContext> contexts = new MultiValueMap<>();
|
public MultiValueMap<Instruction, InstructionContext> contexts = new MultiValueMap<>(); // XXX this should move to method ctx probably
|
||||||
public boolean paused;
|
public boolean paused;
|
||||||
public boolean step = false;
|
public boolean step = false;
|
||||||
|
private List<ExecutionVisitor> visitors = new ArrayList<>();
|
||||||
|
|
||||||
public Execution(ClassGroup group)
|
public Execution(ClassGroup group)
|
||||||
{
|
{
|
||||||
@@ -76,11 +76,11 @@ public class Execution
|
|||||||
|
|
||||||
public boolean hasInvoked(InstructionContext from, Method to)
|
public boolean hasInvoked(InstructionContext from, Method to)
|
||||||
{
|
{
|
||||||
Collection<Method> methods = invokes.getCollection(from);
|
Collection<Method> methods = invokes.getCollection(from.toWeak());
|
||||||
if (methods != null && methods.contains(to))
|
if (methods != null && methods.contains(to))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
invokes.put(from, to);
|
invokes.put(from.toWeak(), to);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +128,6 @@ public class Execution
|
|||||||
assert !frame.isExecuting();
|
assert !frame.isExecuting();
|
||||||
|
|
||||||
frames.remove(frame);
|
frames.remove(frame);
|
||||||
processedFrames.add(frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Processed " + fcount + " frames");
|
System.out.println("Processed " + fcount + " frames");
|
||||||
@@ -138,4 +137,14 @@ public class Execution
|
|||||||
{
|
{
|
||||||
return contexts.getCollection(i);
|
return contexts.getCollection(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addExecutionVisitor(ExecutionVisitor ev)
|
||||||
|
{
|
||||||
|
this.visitors.add(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accept(InstructionContext ic)
|
||||||
|
{
|
||||||
|
visitors.forEach(v -> v.visit(ic));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package net.runelite.asm.execution;
|
||||||
|
|
||||||
|
public interface ExecutionVisitor
|
||||||
|
{
|
||||||
|
void visit(InstructionContext context);
|
||||||
|
}
|
||||||
@@ -239,6 +239,8 @@ public class Frame
|
|||||||
execution.contexts.put(oldCur, ictx);
|
execution.contexts.put(oldCur, ictx);
|
||||||
|
|
||||||
execution.executed.add(oldCur);
|
execution.executed.add(oldCur);
|
||||||
|
|
||||||
|
execution.accept(ictx);
|
||||||
|
|
||||||
processExceptions(ictx);
|
processExceptions(ictx);
|
||||||
|
|
||||||
|
|||||||
@@ -209,4 +209,20 @@ public class InstructionContext
|
|||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WeakInstructionContext toWeak()
|
||||||
|
{
|
||||||
|
WeakInstructionContext wic = new WeakInstructionContext(this.getInstruction());
|
||||||
|
|
||||||
|
for (StackContext sctx : stack.getStack())
|
||||||
|
{
|
||||||
|
if (sctx == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
InstructionContext i = sctx.getPushed();
|
||||||
|
wic.addStack(i.getInstruction());
|
||||||
|
}
|
||||||
|
|
||||||
|
return wic;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package net.runelite.asm.execution;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.runelite.asm.attributes.code.Instruction;
|
||||||
|
|
||||||
|
public class WeakInstructionContext
|
||||||
|
{
|
||||||
|
private Instruction ins;
|
||||||
|
private List<Instruction> stack = new ArrayList<>();
|
||||||
|
|
||||||
|
public WeakInstructionContext(Instruction ins)
|
||||||
|
{
|
||||||
|
this.ins = ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addStack(Instruction i)
|
||||||
|
{
|
||||||
|
stack.add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
int hash = 3;
|
||||||
|
hash = 37 * hash + Objects.hashCode(this.ins);
|
||||||
|
hash = 37 * hash + Objects.hashCode(this.stack);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final WeakInstructionContext other = (WeakInstructionContext) obj;
|
||||||
|
if (!Objects.equals(this.ins, other.ins))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.stack, other.stack))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,8 @@ class ConstantMethodParameter
|
|||||||
public int paramIndex;
|
public int paramIndex;
|
||||||
public int lvtIndex;
|
public int lvtIndex;
|
||||||
public Object value;
|
public Object value;
|
||||||
|
List<InstructionContext> operations = new ArrayList<>();
|
||||||
|
Boolean result;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
@@ -88,6 +90,8 @@ class MethodGroup
|
|||||||
public class ConstantParameter implements Deobfuscator
|
public class ConstantParameter implements Deobfuscator
|
||||||
{
|
{
|
||||||
private List<ConstantMethodParameter> parameters = new ArrayList<>();
|
private List<ConstantMethodParameter> parameters = new ArrayList<>();
|
||||||
|
private MultiValueMap<Method, ConstantMethodParameter> mparams = new MultiValueMap<>();
|
||||||
|
|
||||||
private MultiValueMap<Method, Integer> nonconst = new MultiValueMap<>(); // methods with non const parameters
|
private MultiValueMap<Method, Integer> nonconst = new MultiValueMap<>(); // methods with non const parameters
|
||||||
private List<MethodGroup> methodGroups = new ArrayList<>();
|
private List<MethodGroup> methodGroups = new ArrayList<>();
|
||||||
|
|
||||||
@@ -105,8 +109,10 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findConstantParameter(Execution execution, List<Method> methods, InstructionContext invokeCtx)
|
private List<ConstantMethodParameter> findConstantParameter(List<Method> methods, InstructionContext invokeCtx)
|
||||||
{
|
{
|
||||||
|
List<ConstantMethodParameter> list = new ArrayList<>();
|
||||||
|
|
||||||
checkMethodsAreConsistent(methods);
|
checkMethodsAreConsistent(methods);
|
||||||
|
|
||||||
Method method = methods.get(0); // all methods must have the same signature etc
|
Method method = methods.get(0); // all methods must have the same signature etc
|
||||||
@@ -149,6 +155,10 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
continue outer;
|
continue outer;
|
||||||
|
|
||||||
parameters.add(cmp);
|
parameters.add(cmp);
|
||||||
|
for (Method m : methods)
|
||||||
|
mparams.put(m, cmp);
|
||||||
|
|
||||||
|
list.add(cmp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -162,28 +172,152 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
if (c.methods.equals(methods) && c.lvtIndex == lvtOffset)
|
if (c.methods.equals(methods) && c.lvtIndex == lvtOffset)
|
||||||
{
|
{
|
||||||
it.remove();
|
it.remove();
|
||||||
|
list.remove(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findParameters(Execution execution)
|
private void findParameters(InstructionContext ins)
|
||||||
{
|
{
|
||||||
for (Frame frame : execution.processedFrames)
|
if (!(ins.getInstruction() instanceof InvokeInstruction))
|
||||||
for (InstructionContext ins : frame.getInstructions())
|
return;
|
||||||
{
|
|
||||||
if (!(ins.getInstruction() instanceof InvokeInstruction))
|
List<Method> methods = ((InvokeInstruction) ins.getInstruction()).getMethods();
|
||||||
continue;
|
if (methods.isEmpty())
|
||||||
|
return;
|
||||||
List<Method> methods = ((InvokeInstruction) ins.getInstruction()).getMethods();
|
|
||||||
if (methods.isEmpty())
|
findConstantParameter(methods, ins);
|
||||||
continue;
|
//findDeadParameters(ins, c);
|
||||||
|
|
||||||
findConstantParameter(execution, methods, ins);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ConstantMethodParameter> findParametersForMethod(Method m)
|
||||||
|
{
|
||||||
|
Collection c = mparams.getCollection(m);
|
||||||
|
if (c == null) return new ArrayList();
|
||||||
|
return new ArrayList(c);
|
||||||
|
// List<ConstantMethodParameter> list = new ArrayList<>();
|
||||||
|
// for (ConstantMethodParameter c : parameters)
|
||||||
|
// if (c.methods.contains(m))
|
||||||
|
// list.add(c);
|
||||||
|
// return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findDeadParameters(InstructionContext ins)
|
||||||
|
{
|
||||||
|
List<ConstantMethodParameter> parameters = this.findParametersForMethod(ins.getFrame().getMethod());
|
||||||
|
|
||||||
|
for (ConstantMethodParameter parameter : parameters)
|
||||||
|
{
|
||||||
|
int lvtIndex = parameter.lvtIndex;
|
||||||
|
Object value = parameter.value;
|
||||||
|
|
||||||
|
if (ins.getInstruction() instanceof LVTInstruction)
|
||||||
|
{
|
||||||
|
LVTInstruction lvt = (LVTInstruction) ins.getInstruction();
|
||||||
|
|
||||||
|
if (lvt.getVariableIndex() == lvtIndex && lvt.store())
|
||||||
|
{
|
||||||
|
this.parameters.remove(parameter);
|
||||||
|
continue; // parameter is used
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ins.getInstruction() instanceof ComparisonInstruction))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume that this will always be variable index #paramIndex comp with a constant.
|
||||||
|
ComparisonInstruction comp = (ComparisonInstruction) ins.getInstruction();
|
||||||
|
|
||||||
|
StackContext one, two = null;
|
||||||
|
|
||||||
|
if (comp instanceof If0)
|
||||||
|
{
|
||||||
|
one = ins.getPops().get(0);
|
||||||
|
}
|
||||||
|
else if (comp instanceof If)
|
||||||
|
{
|
||||||
|
one = ins.getPops().get(0);
|
||||||
|
two = ins.getPops().get(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Unknown comp ins");
|
||||||
|
}
|
||||||
|
|
||||||
|
// find if one is a lvt ins
|
||||||
|
LVTInstruction lvt = null;
|
||||||
|
StackContext other = null;
|
||||||
|
|
||||||
|
if (one.getPushed().getInstruction() instanceof LVTInstruction)
|
||||||
|
{
|
||||||
|
lvt = (LVTInstruction) one.getPushed().getInstruction();
|
||||||
|
other = two;
|
||||||
|
}
|
||||||
|
else if (two != null && two.getPushed().getInstruction() instanceof LVTInstruction)
|
||||||
|
{
|
||||||
|
lvt = (LVTInstruction) two.getPushed().getInstruction();
|
||||||
|
other = one;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert lvt == null || !lvt.store();
|
||||||
|
|
||||||
|
if (lvt == null || lvt.getVariableIndex() != lvtIndex)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object otherValue = null;
|
||||||
|
|
||||||
|
if (two != null) // two is null for if0
|
||||||
|
{
|
||||||
|
if (!(other.getPushed().getInstruction() instanceof PushConstantInstruction))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PushConstantInstruction pc = (PushConstantInstruction) other.getPushed().getInstruction();
|
||||||
|
otherValue = pc.getConstant().getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// the result of the comparison doesn't matter, only that it always goes the same direction for every invocation
|
||||||
|
boolean result = doLogicalComparison(value, comp, otherValue);
|
||||||
|
|
||||||
|
if (parameter.result != null && parameter.result != result)
|
||||||
|
{
|
||||||
|
this.parameters.remove(parameter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parameter.operations.add(ins);
|
||||||
|
parameter.result = result;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Boolean b = deadOps.get(ins.getInstruction());
|
||||||
|
// if (b != null)
|
||||||
|
// {
|
||||||
|
// if (b != result)
|
||||||
|
// {
|
||||||
|
// //deadOps.remove(ins.getInstruction());
|
||||||
|
// this.parameters.remove(parameter);
|
||||||
|
// //invalidDeadOps.add(ins.getInstruction());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// deadOps.put(ins.getInstruction(), result);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//private Map<Instruction, Boolean> deadOps = new HashMap<>();
|
||||||
|
// private Set<Instruction> invalidDeadOps = new HashSet<>();
|
||||||
|
|
||||||
private boolean doLogicalComparison(Object value, ComparisonInstruction comparison, Object otherValue)
|
private boolean doLogicalComparison(Object value, ComparisonInstruction comparison, Object otherValue)
|
||||||
{
|
{
|
||||||
Instruction ins = (Instruction) comparison;
|
Instruction ins = (Instruction) comparison;
|
||||||
@@ -252,93 +386,93 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find all comparisons of lvtIndex in method and record branch taken
|
// find all comparisons of lvtIndex in method and record branch taken
|
||||||
private List<LogicallyDeadOp> isLogicallyDead(Execution execution, Method method, int lvtIndex, Object value)
|
// private List<LogicallyDeadOp> isLogicallyDead(Execution execution, Method method, int lvtIndex, Object value)
|
||||||
{
|
// {
|
||||||
List<LogicallyDeadOp> ops = new ArrayList<>();
|
// List<LogicallyDeadOp> ops = new ArrayList<>();
|
||||||
|
//
|
||||||
for (Frame frame : execution.processedFrames)
|
// for (Frame frame : execution.processedFrames)
|
||||||
{
|
// {
|
||||||
if (frame.getMethod() != method)
|
// if (frame.getMethod() != method)
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
for (InstructionContext ins : frame.getInstructions())
|
// for (InstructionContext ins : frame.getInstructions())
|
||||||
{
|
// {
|
||||||
if (ins.getInstruction() instanceof LVTInstruction)
|
// if (ins.getInstruction() instanceof LVTInstruction)
|
||||||
{
|
// {
|
||||||
LVTInstruction lvt = (LVTInstruction) ins.getInstruction();
|
// LVTInstruction lvt = (LVTInstruction) ins.getInstruction();
|
||||||
|
//
|
||||||
if (lvt.getVariableIndex() == lvtIndex && lvt.store())
|
// if (lvt.getVariableIndex() == lvtIndex && lvt.store())
|
||||||
{
|
// {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (!(ins.getInstruction() instanceof ComparisonInstruction))
|
// if (!(ins.getInstruction() instanceof ComparisonInstruction))
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
// assume that this will always be variable index #paramIndex comp with a constant.
|
// // assume that this will always be variable index #paramIndex comp with a constant.
|
||||||
|
//
|
||||||
ComparisonInstruction comp = (ComparisonInstruction) ins.getInstruction();
|
// ComparisonInstruction comp = (ComparisonInstruction) ins.getInstruction();
|
||||||
|
//
|
||||||
StackContext one, two = null;
|
// StackContext one, two = null;
|
||||||
|
//
|
||||||
if (comp instanceof If0)
|
// if (comp instanceof If0)
|
||||||
{
|
// {
|
||||||
one = ins.getPops().get(0);
|
// one = ins.getPops().get(0);
|
||||||
}
|
// }
|
||||||
else if (comp instanceof If)
|
// else if (comp instanceof If)
|
||||||
{
|
// {
|
||||||
one = ins.getPops().get(0);
|
// one = ins.getPops().get(0);
|
||||||
two = ins.getPops().get(1);
|
// two = ins.getPops().get(1);
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
throw new RuntimeException("Unknown comp ins");
|
// throw new RuntimeException("Unknown comp ins");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// find if one is a lvt ins
|
// // find if one is a lvt ins
|
||||||
LVTInstruction lvt = null;
|
// LVTInstruction lvt = null;
|
||||||
StackContext other = null;
|
// StackContext other = null;
|
||||||
|
//
|
||||||
if (one.getPushed().getInstruction() instanceof LVTInstruction)
|
// if (one.getPushed().getInstruction() instanceof LVTInstruction)
|
||||||
{
|
// {
|
||||||
lvt = (LVTInstruction) one.getPushed().getInstruction();
|
// lvt = (LVTInstruction) one.getPushed().getInstruction();
|
||||||
other = two;
|
// other = two;
|
||||||
}
|
// }
|
||||||
else if (two != null && two.getPushed().getInstruction() instanceof LVTInstruction)
|
// else if (two != null && two.getPushed().getInstruction() instanceof LVTInstruction)
|
||||||
{
|
// {
|
||||||
lvt = (LVTInstruction) two.getPushed().getInstruction();
|
// lvt = (LVTInstruction) two.getPushed().getInstruction();
|
||||||
other = one;
|
// other = one;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
assert lvt == null || !lvt.store();
|
// assert lvt == null || !lvt.store();
|
||||||
|
//
|
||||||
if (lvt == null || lvt.getVariableIndex() != lvtIndex)
|
// if (lvt == null || lvt.getVariableIndex() != lvtIndex)
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
Object otherValue = null;
|
// Object otherValue = null;
|
||||||
|
//
|
||||||
if (two != null) // two is null for if0
|
// if (two != null) // two is null for if0
|
||||||
{
|
// {
|
||||||
if (!(other.getPushed().getInstruction() instanceof PushConstantInstruction))
|
// if (!(other.getPushed().getInstruction() instanceof PushConstantInstruction))
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
PushConstantInstruction pc = (PushConstantInstruction) other.getPushed().getInstruction();
|
// PushConstantInstruction pc = (PushConstantInstruction) other.getPushed().getInstruction();
|
||||||
otherValue = pc.getConstant().getObject();
|
// otherValue = pc.getConstant().getObject();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// the result of the comparison doesn't matter, only that it always goes the same direction for every invocation
|
// // the result of the comparison doesn't matter, only that it always goes the same direction for every invocation
|
||||||
boolean result = doLogicalComparison(value, comp, otherValue);
|
// boolean result = doLogicalComparison(value, comp, otherValue);
|
||||||
|
//
|
||||||
LogicallyDeadOp deadOp = new LogicallyDeadOp();
|
// LogicallyDeadOp deadOp = new LogicallyDeadOp();
|
||||||
deadOp.compCtx = ins;
|
// deadOp.compCtx = ins;
|
||||||
deadOp.branch = result;
|
// deadOp.branch = result;
|
||||||
ops.add(deadOp);
|
// ops.add(deadOp);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return ops;
|
// return ops;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static class MethodLvtPair
|
private static class MethodLvtPair
|
||||||
{
|
{
|
||||||
@@ -368,20 +502,25 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj)
|
public boolean equals(Object obj)
|
||||||
{
|
{
|
||||||
if (obj == null) {
|
if (obj == null)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getClass() != obj.getClass()) {
|
if (getClass() != obj.getClass())
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final MethodLvtPair other = (MethodLvtPair) obj;
|
final MethodLvtPair other = (MethodLvtPair) obj;
|
||||||
if (!Objects.equals(this.method, other.method)) {
|
if (!Objects.equals(this.method, other.method))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.lvtIndex != other.lvtIndex) {
|
if (this.lvtIndex != other.lvtIndex)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.paramIndex != other.paramIndex) {
|
if (this.paramIndex != other.paramIndex)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -389,71 +528,67 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
//
|
||||||
private Map<MethodLvtPair, List<LogicallyDeadOp> > deadops = new HashMap<>();
|
// private Map<MethodLvtPair, List<LogicallyDeadOp> > deadops = new HashMap<>();
|
||||||
private Set<MethodLvtPair> invalidDeadops = new HashSet<>();
|
// private Set<MethodLvtPair> invalidDeadops = new HashSet<>();
|
||||||
|
|
||||||
// check every method parameter that we've identified as being passed constants to see if it's logically dead
|
// check every method parameter that we've identified as being passed constants to see if it's logically dead
|
||||||
private void findLogicallyDeadOperations(Execution execution)
|
// private void findLogicallyDeadOperations(Execution execution)
|
||||||
{
|
// {
|
||||||
outer:
|
// for (ConstantMethodParameter cmp : parameters)
|
||||||
for (ConstantMethodParameter cmp : parameters)
|
// {
|
||||||
{
|
// for (Method method : cmp.methods)
|
||||||
for (Method method : cmp.methods)
|
// {
|
||||||
{
|
// MethodLvtPair pair = new MethodLvtPair(method, cmp.lvtIndex, cmp.paramIndex, cmp.value);
|
||||||
MethodLvtPair pair = new MethodLvtPair(method, cmp.lvtIndex, cmp.paramIndex, cmp.value);
|
//
|
||||||
|
// if (invalidDeadops.contains(pair))
|
||||||
if (invalidDeadops.contains(pair))
|
// continue;
|
||||||
continue;
|
//
|
||||||
|
// // the dead comparisons must be the same and branch the same way for every call to this method.
|
||||||
// the dead comparisons must be the same and branch the same way for every call to this method.
|
// List<LogicallyDeadOp> deadOps = isLogicallyDead(execution, method, cmp.lvtIndex, cmp.value);
|
||||||
List<LogicallyDeadOp> deadOps = isLogicallyDead(execution, method, cmp.lvtIndex, cmp.value);
|
//
|
||||||
|
// if (deadOps == null)
|
||||||
if (deadOps == null)
|
// {
|
||||||
{
|
// deadops.remove(pair);
|
||||||
deadops.remove(pair);
|
// invalidDeadops.add(pair);
|
||||||
invalidDeadops.add(pair);
|
// continue; // lvt store
|
||||||
continue; // lvt store
|
// }
|
||||||
}
|
//
|
||||||
|
// if (deadOps.isEmpty())
|
||||||
if (deadOps.isEmpty())
|
// continue; // no ops to compare
|
||||||
continue; // no ops to compare
|
//
|
||||||
|
// // this must be per method,lvtindex
|
||||||
// this must be per method,lvtindex
|
// List<LogicallyDeadOp> existing = deadops.get(pair);
|
||||||
List<LogicallyDeadOp> existing = deadops.get(pair);
|
// if (existing != null)
|
||||||
if (existing != null)
|
// if (!existing.equals(deadOps))
|
||||||
if (!existing.equals(deadOps))
|
// {
|
||||||
{
|
// // one of the branches taken differs because of the value, skip it
|
||||||
// one of the branches taken differs because of the value, skip it
|
// deadops.remove(pair);
|
||||||
deadops.remove(pair);
|
// invalidDeadops.add(pair);
|
||||||
invalidDeadops.add(pair);
|
// continue;
|
||||||
continue;
|
// }
|
||||||
}
|
// else
|
||||||
else
|
// {
|
||||||
{
|
// continue;
|
||||||
continue;
|
// }
|
||||||
}
|
//
|
||||||
|
// deadops.put(pair, deadOps);
|
||||||
deadops.put(pair, deadOps);
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
// remove logically dead comparisons
|
// remove logically dead comparisons
|
||||||
private int removeDeadOperations()
|
private int removeDeadOperations()
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (MethodLvtPair mvp : deadops.keySet())
|
for (ConstantMethodParameter cmp : parameters)
|
||||||
{
|
{
|
||||||
List<LogicallyDeadOp> ops = deadops.get(mvp);
|
annotateObfuscatedSignature(cmp);
|
||||||
|
|
||||||
annotateObfuscatedSignature(mvp);
|
for (InstructionContext ctx : cmp.operations) // comparisons
|
||||||
|
|
||||||
for (LogicallyDeadOp op : ops)
|
|
||||||
{
|
{
|
||||||
InstructionContext ctx = op.compCtx; // comparison
|
|
||||||
Instruction ins = ctx.getInstruction();
|
Instruction ins = ctx.getInstruction();
|
||||||
boolean branch = op.branch; // branch that is always taken
|
boolean branch = cmp.result; // branch that is always taken
|
||||||
|
|
||||||
if (ins.getInstructions() == null)
|
if (ins.getInstructions() == null)
|
||||||
continue; // ins already removed?
|
continue; // ins already removed?
|
||||||
@@ -512,23 +647,25 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
|
|
||||||
private static final Type OBFUSCATED_SIGNATURE = new Type("Lnet/runelite/mapping/ObfuscatedSignature;");
|
private static final Type OBFUSCATED_SIGNATURE = new Type("Lnet/runelite/mapping/ObfuscatedSignature;");
|
||||||
|
|
||||||
private void annotateObfuscatedSignature(MethodLvtPair mvp)
|
private void annotateObfuscatedSignature(ConstantMethodParameter parameter)
|
||||||
{
|
{
|
||||||
Method m = mvp.method;
|
for (Method m : parameter.methods)
|
||||||
Object value = mvp.value;
|
{
|
||||||
|
Object value = parameter.value;
|
||||||
|
|
||||||
Attributes attributes = m.getAttributes();
|
Attributes attributes = m.getAttributes();
|
||||||
Annotations annotations = attributes.getAnnotations();
|
Annotations annotations = attributes.getAnnotations();
|
||||||
|
|
||||||
if (annotations != null && annotations.find(OBFUSCATED_SIGNATURE) != null)
|
if (annotations != null && annotations.find(OBFUSCATED_SIGNATURE) != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Annotation annotation = attributes.addAnnotation(OBFUSCATED_SIGNATURE, "signature", new net.runelite.asm.pool.UTF8(m.getDescriptor().toString()));
|
Annotation annotation = attributes.addAnnotation(OBFUSCATED_SIGNATURE, "signature", new net.runelite.asm.pool.UTF8(m.getDescriptor().toString()));
|
||||||
|
|
||||||
Element element = new Element(annotation);
|
Element element = new Element(annotation);
|
||||||
element.setType(new Type("garbageValue"));
|
element.setType(new Type("garbageValue"));
|
||||||
element.setValue(new net.runelite.asm.pool.UTF8(value.toString()));
|
element.setValue(new net.runelite.asm.pool.UTF8(value.toString()));
|
||||||
annotation.addElement(element);
|
annotation.addElement(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -537,11 +674,17 @@ public class ConstantParameter implements Deobfuscator
|
|||||||
group.buildClassGraph(); // required for getMethods in the invoke stuff by execution...
|
group.buildClassGraph(); // required for getMethods in the invoke stuff by execution...
|
||||||
|
|
||||||
Execution execution = new Execution(group);
|
Execution execution = new Execution(group);
|
||||||
|
execution.addExecutionVisitor((i) -> findParameters(i));
|
||||||
|
execution.addExecutionVisitor((i) -> findDeadParameters(i));
|
||||||
execution.populateInitialMethods();
|
execution.populateInitialMethods();
|
||||||
execution.run();
|
execution.run();
|
||||||
|
|
||||||
|
// execution = new Execution(group);
|
||||||
|
// execution.addExecutionVisitor((i) -> findDeadParameters(i));
|
||||||
|
// execution.populateInitialMethods();
|
||||||
|
// execution.run();
|
||||||
|
|
||||||
findParameters(execution);
|
//findLogicallyDeadOperations(execution);
|
||||||
findLogicallyDeadOperations(execution);
|
|
||||||
int count = removeDeadOperations();
|
int count = removeDeadOperations();
|
||||||
|
|
||||||
System.out.println("Removed " + count + " logically dead conditional jumps");
|
System.out.println("Removed " + count + " logically dead conditional jumps");
|
||||||
|
|||||||
Reference in New Issue
Block a user