git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@468 379699f6-c40d-0410-875b-85095c16579estable
parent
c7fbe7c2b9
commit
9267e857f7
@ -0,0 +1,304 @@ |
|||||||
|
package jode.obfuscator; |
||||||
|
import java.util.*; |
||||||
|
import jode.bytecode.*; |
||||||
|
|
||||||
|
public class LocalOptimizer { |
||||||
|
|
||||||
|
class LocalInfo { |
||||||
|
LocalInfo shadow = null; |
||||||
|
|
||||||
|
public LocalInfo getReal() { |
||||||
|
LocalInfo real = this; |
||||||
|
while (real.shadow != null) |
||||||
|
real = real.shadow; |
||||||
|
return real; |
||||||
|
} |
||||||
|
|
||||||
|
Vector usingInstrs = new Vector(); |
||||||
|
Vector conflictingLocals = new Vector(); |
||||||
|
int newSlot = -1; |
||||||
|
|
||||||
|
LocalInfo(InstrInfo instr) { |
||||||
|
usingInstrs.addElement(instr); |
||||||
|
} |
||||||
|
|
||||||
|
void conflictsWith(LocalInfo l) { |
||||||
|
if (shadow != null) { |
||||||
|
getReal().conflictsWith(l); |
||||||
|
} else { |
||||||
|
l = l.getReal(); |
||||||
|
if (!conflictingLocals.contains(l)) { |
||||||
|
conflictingLocals.addElement(l); |
||||||
|
l.conflictingLocals.addElement(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void combineInto(LocalInfo l) { |
||||||
|
if (shadow != null) { |
||||||
|
getReal().combineInto(l); |
||||||
|
return; |
||||||
|
} |
||||||
|
l = l.getReal(); |
||||||
|
if (this == l) |
||||||
|
return; |
||||||
|
shadow = l; |
||||||
|
Enumeration enum = usingInstrs.elements(); |
||||||
|
while (enum.hasMoreElements()) { |
||||||
|
InstrInfo instr = (InstrInfo) enum.nextElement(); |
||||||
|
instr.local = l; |
||||||
|
l.usingInstrs.addElement(instr); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class InstrInfo { |
||||||
|
/** |
||||||
|
* Tell if the localsToRead variable has changed. |
||||||
|
*/ |
||||||
|
boolean changed; |
||||||
|
/** |
||||||
|
* The LocalInfo of the next Instruction, that may read a local, |
||||||
|
* without prior writing. |
||||||
|
*/ |
||||||
|
LocalInfo[] nextReads; |
||||||
|
/** |
||||||
|
* The LocalInfo for this local |
||||||
|
*/ |
||||||
|
LocalInfo local; |
||||||
|
/** |
||||||
|
* The Instruction of this info |
||||||
|
*/ |
||||||
|
Instruction instr; |
||||||
|
/** |
||||||
|
* The next info in the chain. |
||||||
|
*/ |
||||||
|
InstrInfo nextInfo; |
||||||
|
} |
||||||
|
|
||||||
|
InstrInfo firstInfo; |
||||||
|
Hashtable instrInfos; |
||||||
|
BytecodeInfo bc; |
||||||
|
|
||||||
|
public LocalOptimizer(BytecodeInfo bc) { |
||||||
|
this.bc = bc; |
||||||
|
} |
||||||
|
|
||||||
|
public void promoteReads(InstrInfo info, Instruction preInstr) { |
||||||
|
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr); |
||||||
|
int omitLocal = -1; |
||||||
|
if (preInstr.localSlot != -1 |
||||||
|
&& preInstr.opcode >= BytecodeInfo.opc_istore |
||||||
|
&& preInstr.opcode < BytecodeInfo.opc_iastore) { |
||||||
|
/* This is a store */ |
||||||
|
omitLocal = preInstr.localSlot; |
||||||
|
if (info.nextReads[preInstr.localSlot] != null) |
||||||
|
preInfo.local.combineInto |
||||||
|
(info.nextReads[preInstr.localSlot]); |
||||||
|
} |
||||||
|
int maxlocals = bc.getMaxLocals(); |
||||||
|
for (int i=0; i< maxlocals; i++) { |
||||||
|
if (info.nextReads[i] != null && i != omitLocal) { |
||||||
|
if (preInfo.nextReads[i] == null) { |
||||||
|
preInfo.nextReads[i] = info.nextReads[i]; |
||||||
|
preInfo.changed = true; |
||||||
|
} else { |
||||||
|
preInfo.nextReads[i] |
||||||
|
.combineInto(info.nextReads[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void calcLocalInfo() { |
||||||
|
int maxlocals = bc.getMaxLocals(); |
||||||
|
Handler[] handlers = bc.getExceptionHandlers(); |
||||||
|
/* Initialize the InstrInfos and LocalInfos |
||||||
|
*/ |
||||||
|
instrInfos = new Hashtable(); |
||||||
|
{ |
||||||
|
InstrInfo info = firstInfo = new InstrInfo(); |
||||||
|
Instruction instr = bc.getFirstInstr(); |
||||||
|
while (true) { |
||||||
|
instrInfos.put(instr, info); |
||||||
|
info.instr = instr; |
||||||
|
info.nextReads = new LocalInfo[maxlocals]; |
||||||
|
if (instr.localSlot != -1) { |
||||||
|
info.local = new LocalInfo(info); |
||||||
|
if (instr.opcode < BytecodeInfo.opc_istore |
||||||
|
|| instr.opcode > BytecodeInfo.opc_iastore) { |
||||||
|
/* this is a load instruction */ |
||||||
|
info.nextReads[instr.localSlot] = info.local; |
||||||
|
info.changed = true; |
||||||
|
} |
||||||
|
} |
||||||
|
if ((instr = instr.nextByAddr) == null) |
||||||
|
break; |
||||||
|
info = info.nextInfo = new InstrInfo(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* find out which locals are the same. |
||||||
|
*/ |
||||||
|
boolean changed = true; |
||||||
|
while (changed) { |
||||||
|
changed = false; |
||||||
|
for (InstrInfo info = firstInfo; |
||||||
|
info != null; info = info.nextInfo) { |
||||||
|
if (info.changed) { |
||||||
|
info.changed = false; |
||||||
|
Enumeration enum = info.instr.preds.elements(); |
||||||
|
while (enum.hasMoreElements()) { |
||||||
|
changed = true; |
||||||
|
Instruction preInstr |
||||||
|
= (Instruction) enum.nextElement(); |
||||||
|
promoteReads(info, preInstr); |
||||||
|
} |
||||||
|
for (int i=0; i<handlers.length; i++) { |
||||||
|
if (handlers[i].catcher == info.instr) { |
||||||
|
for (Instruction preInstr = handlers[i].start; |
||||||
|
preInstr != handlers[i].end; |
||||||
|
preInstr = preInstr.nextByAddr) { |
||||||
|
promoteReads(info, preInstr); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Now calculate the conflict settings. |
||||||
|
*/ |
||||||
|
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
||||||
|
if (info.instr.localSlot != -1 |
||||||
|
&& info.instr.opcode >= BytecodeInfo.opc_istore |
||||||
|
&& info.instr.opcode < BytecodeInfo.opc_iastore) { |
||||||
|
/* This is a store. It conflicts with every local, whose |
||||||
|
* value will be read without write. |
||||||
|
*/ |
||||||
|
for (int i=0; i < maxlocals; i++) { |
||||||
|
if (i != info.instr.localSlot |
||||||
|
&& info.nextReads[i] != null) |
||||||
|
info.local.conflictsWith(info.nextReads[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void distributeLocals(Vector locals) { |
||||||
|
if (locals.size() == 0) |
||||||
|
return; |
||||||
|
|
||||||
|
/* Find the local with the least conflicts. */ |
||||||
|
int min = Integer.MAX_VALUE; |
||||||
|
LocalInfo bestLocal = null; |
||||||
|
Enumeration enum = locals.elements(); |
||||||
|
while (enum.hasMoreElements()) { |
||||||
|
LocalInfo li = (LocalInfo) enum.nextElement(); |
||||||
|
int conflicts = 0; |
||||||
|
Enumeration conflenum = li.conflictingLocals.elements(); |
||||||
|
while (conflenum.hasMoreElements()) { |
||||||
|
if (((LocalInfo)conflenum.nextElement()).newSlot != -2) |
||||||
|
conflicts++; |
||||||
|
} |
||||||
|
if (conflicts < min) { |
||||||
|
min = conflicts; |
||||||
|
bestLocal = li; |
||||||
|
} |
||||||
|
} |
||||||
|
/* Mark the local as taken */ |
||||||
|
locals.removeElement(bestLocal); |
||||||
|
bestLocal.newSlot = -2; |
||||||
|
/* Now distribute the remaining locals recursively. */ |
||||||
|
distributeLocals(locals); |
||||||
|
|
||||||
|
/* Finally find a new slot */ |
||||||
|
next_slot: |
||||||
|
for (int slot = 0; ; slot++) { |
||||||
|
Enumeration conflenum = bestLocal.conflictingLocals.elements(); |
||||||
|
while (conflenum.hasMoreElements()) { |
||||||
|
if (((LocalInfo)conflenum.nextElement()).newSlot == slot) |
||||||
|
continue next_slot; |
||||||
|
} |
||||||
|
bestLocal.newSlot = slot; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void distributeLocals() { |
||||||
|
/* give locals new slots. This is a graph coloring |
||||||
|
* algorithm (the optimal solution is NP complete, but this |
||||||
|
* should be a good approximation). |
||||||
|
*/ |
||||||
|
int maxlocals = bc.getMaxLocals(); |
||||||
|
|
||||||
|
|
||||||
|
/* first give the params the same slot as they had before. |
||||||
|
* The params should be the locals in firstInfo.nextReads |
||||||
|
*/ |
||||||
|
for (int i=0; i< maxlocals; i++) { |
||||||
|
if (firstInfo.nextReads[i] != null) |
||||||
|
firstInfo.nextReads[i].getReal().newSlot = i; |
||||||
|
} |
||||||
|
|
||||||
|
/* Now put the locals that need a color into a vector. |
||||||
|
*/ |
||||||
|
Vector locals = new Vector(); |
||||||
|
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
||||||
|
if (info.local != null |
||||||
|
&& info.local.newSlot == -1 |
||||||
|
&& !locals.contains(info.local)) |
||||||
|
locals.addElement(info.local); |
||||||
|
} |
||||||
|
|
||||||
|
/* Now distribute slots recursive. |
||||||
|
*/ |
||||||
|
distributeLocals(locals); |
||||||
|
|
||||||
|
/* Update the instructions. |
||||||
|
*/ |
||||||
|
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
||||||
|
if (info.local != null) |
||||||
|
info.instr.localSlot = info.local.newSlot; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void dumpLocals() { |
||||||
|
Vector locals = new Vector(); |
||||||
|
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { |
||||||
|
// System.err.print("addr: "+info.instr.addr+ " locals: ");
|
||||||
|
// for (int i=0; i<bc.info.getMaxLocals(); i++)
|
||||||
|
// if (info.nextReads[i] == null)
|
||||||
|
// System.err.print("-,");
|
||||||
|
// else
|
||||||
|
// System.err.print(((InstrInfo)info.nextReads[i]
|
||||||
|
// .usingInstrs.elementAt(0)).instr.addr
|
||||||
|
// +",");
|
||||||
|
// System.err.println();
|
||||||
|
if (info.local != null && !locals.contains(info.local)) |
||||||
|
locals.addElement(info.local); |
||||||
|
} |
||||||
|
Enumeration enum = locals.elements(); |
||||||
|
while (enum.hasMoreElements()) { |
||||||
|
LocalInfo li = (LocalInfo) enum.nextElement(); |
||||||
|
int slot = ((InstrInfo)li.usingInstrs.elementAt(0)) |
||||||
|
.instr.localSlot; |
||||||
|
System.err.print("Slot: "+slot+" conflicts:"); |
||||||
|
Enumeration enum1 = li.conflictingLocals.elements(); |
||||||
|
while (enum1.hasMoreElements()) { |
||||||
|
LocalInfo cfl = (LocalInfo)enum1.nextElement(); |
||||||
|
System.err.print(((InstrInfo)cfl.usingInstrs.elementAt(0)) |
||||||
|
.instr.addr+", "); |
||||||
|
} |
||||||
|
System.err.println(); |
||||||
|
System.err.print(((InstrInfo)li.usingInstrs.elementAt(0)) |
||||||
|
.instr.addr); |
||||||
|
System.err.print(" instrs: "); |
||||||
|
Enumeration enum2 = li.usingInstrs.elements(); |
||||||
|
while (enum2.hasMoreElements()) |
||||||
|
System.err.print(((InstrInfo)enum2.nextElement()).instr.addr+", "); |
||||||
|
System.err.println(); |
||||||
|
} |
||||||
|
System.err.println("-----------"); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue