From 9267e857f72d433811d7605656f2ba1d4eda911e Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 20 Mar 1999 00:36:45 +0000 Subject: [PATCH] Initial revision git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@468 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/obfuscator/LocalOptimizer.java | 304 +++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 jode/jode/obfuscator/LocalOptimizer.java diff --git a/jode/jode/obfuscator/LocalOptimizer.java b/jode/jode/obfuscator/LocalOptimizer.java new file mode 100644 index 0000000..b0c1846 --- /dev/null +++ b/jode/jode/obfuscator/LocalOptimizer.java @@ -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= 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