diff --git a/jode/jode/obfuscator/ConstantAnalyzer.java.in b/jode/jode/obfuscator/ConstantAnalyzer.java.in index 0051278..5dd5ad4 100644 --- a/jode/jode/obfuscator/ConstantAnalyzer.java.in +++ b/jode/jode/obfuscator/ConstantAnalyzer.java.in @@ -45,7 +45,6 @@ import @COLLECTIONS@.ListIterator; * @author Jochen Hoenicke */ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { - Map constInfos; BytecodeInfo bytecode; @@ -65,18 +64,25 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { private final static int CMP_EQUAL_MASK = (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ); - final static int REACHABLE = 0x1; - final static int CONSTANT = 0x2; - final static int CONSTANTFLOW = 0x4; + final static int CONSTANT = 0x02; + final static int CONSTANTFLOW = 0x04; + final static int RETASTORE = 0x08; + final static int RETURNINGJSR = 0x10; private interface ConstantListener { public void constantChanged(); } - private static class JSRTargetInfo implements Cloneable { + private final static class JSRTargetInfo implements Cloneable { Instruction jsrTarget; BitSet usedLocals; - StackLocalInfo retInfo = null; + + /** + * The dependent entries, that want to know if the bit set changed. + * This is either a StackLocalInfo (the ret info) or a single + * JSRTargetInfo or a Collection of JSRTargetInfos. + */ + Object dependent; public JSRTargetInfo(Instruction target) { jsrTarget = target; @@ -87,28 +93,65 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { try { JSRTargetInfo result = (JSRTargetInfo) clone(); result.usedLocals = (BitSet) usedLocals.clone(); + addDependent(result); return result; } catch (CloneNotSupportedException ex) { throw new IncompatibleClassChangeError(ex.getMessage()); } } + private void addDependent(JSRTargetInfo result) { + if (dependent == null || dependent == result) + dependent = result; + else if (dependent instanceof JSRTargetInfo) { + Set newDeps = new HashSet(); + newDeps.add(dependent); + newDeps.add(result); + } else if (dependent instanceof Collection) { + ((Collection) dependent).add(result); + } + } + + public void setRetInfo(StackLocalInfo retInfo) { + dependent = retInfo; + } + + public boolean uses(int localSlot) { + return usedLocals.get(localSlot); + } + + public void addUsed(int localSlot) { + if (usedLocals.get(localSlot)) + return; + usedLocals.set(localSlot); + + if (dependent instanceof StackLocalInfo) + ((StackLocalInfo) dependent).enqueue(); + else if (dependent instanceof JSRTargetInfo) + ((JSRTargetInfo) dependent).addUsed(localSlot); + else if (dependent instanceof Collection) { + Iterator iter = ((Collection) dependent).iterator(); + while (iter.hasNext()) { + JSRTargetInfo dep = (JSRTargetInfo) iter.next(); + dep.addUsed(localSlot); + } + } + } + public void merge(JSRTargetInfo o) { - BitSet used = (BitSet) usedLocals.clone(); - used.or(o.usedLocals); - if (retInfo != null) { - if (o.retInfo != null && o.retInfo != retInfo) - throw new AssertError("retInfos differ"); - o.retInfo = retInfo; - retInfo.enqueue(); + o.addDependent(this); + for (int slot = 0; slot < o.usedLocals.size(); slot++) { + if (o.usedLocals.get(slot)) + addUsed(slot); } } public String toString() { StringBuffer sb = new StringBuffer(String.valueOf(jsrTarget)); - if (retInfo != null) - sb.append("->").append(retInfo.instr); - return sb.append(usedLocals).toString(); + if (dependent instanceof StackLocalInfo) + sb.append("->").append(((StackLocalInfo) dependent).instr); + return sb.append(usedLocals) + .append('_').append(hashCode()).toString(); } } @@ -180,8 +223,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { if (this == other) return; - if (value == other.value - || (value != null && value.equals(other.value))) { + if (value == null ? other.value == null + : value.equals(other.value)) { if (value != VOLATILE) { // other.addConstantListener(this); this.addConstantListener(other); @@ -190,11 +233,13 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { } if (value instanceof JSRTargetInfo - && other.value instanceof JSRTargetInfo) { + && other.value instanceof JSRTargetInfo + && (((JSRTargetInfo) value).jsrTarget + == ((JSRTargetInfo) other.value).jsrTarget)) { ((JSRTargetInfo) value).merge((JSRTargetInfo) other.value); return; } - + if (value != VOLATILE) fireChanged(); // if (other.value != VOLATILE) @@ -214,6 +259,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { ConstValue[] stack; ConstValue[] locals; Instruction instr; + ConstantInfo constInfo; + StackLocalInfo retInfo; StackLocalInfo nextOnQueue; @@ -333,20 +380,65 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { for (int i=0; i< locals.length; i++) { if (locals[i] != null && locals[i].value instanceof JSRTargetInfo) { - locals[i] = locals[i].copy(); - locals[i].value = ((JSRTargetInfo) locals[i].value).copy(); - ((JSRTargetInfo)locals[i].value).usedLocals.set(slot); + JSRTargetInfo jsrInfo = (JSRTargetInfo)locals[i].value; + if (!jsrInfo.uses(slot)) { + jsrInfo = jsrInfo.copy(); + locals[i] = locals[i].copy(); + locals[i].value = jsrInfo; + jsrInfo.addUsed(slot); + } } } for (int i=0; i< stack.length; i++) { if (stack[i] != null && stack[i].value instanceof JSRTargetInfo) { + JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value; + if (!jsrInfo.uses(slot)) { + jsrInfo = jsrInfo.copy(); + stack[i] = stack[i].copy(); + stack[i].value = jsrInfo; + jsrInfo.addUsed(slot); + } + } + } + return this; + } + + public StackLocalInfo mergeRetLocals(JSRTargetInfo jsrTargetInfo, + StackLocalInfo retInfo) { + for (int slot = 0; slot < locals.length; slot++) { + if (jsrTargetInfo.uses(slot)) + locals[slot] = retInfo.locals[slot]; + } + locals[retInfo.instr.getLocalSlot()] = null; + + for (int i=0; i< locals.length; i++) { + if (locals[i] != null + && locals[i].value instanceof JSRTargetInfo) { + JSRTargetInfo jsrInfo = (JSRTargetInfo) locals[i].value; + jsrInfo = jsrInfo.copy(); locals[i] = locals[i].copy(); - locals[i].value = ((JSRTargetInfo)locals[i].value).copy(); - ((JSRTargetInfo)locals[i].value).usedLocals.set(slot); + locals[i].value = jsrInfo; + for (int slot = 0; slot < locals.length; slot++) { + if (jsrTargetInfo.uses(slot)) + jsrInfo.addUsed(slot); + } } } - return new StackLocalInfo(stack, locals, notifyQueue); + for (int i=0; i< stack.length; i++) { + if (stack[i] != null + && stack[i].value instanceof JSRTargetInfo) { + JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value; + jsrInfo = jsrInfo.copy(); + stack[i] = stack[i].copy(); + stack[i].value = jsrInfo; + for (int slot = 0; slot < locals.length; slot++) { + if (jsrTargetInfo.uses(slot)) + jsrInfo.addUsed(slot); + } + } + } + return this; } public void merge(StackLocalInfo other) { @@ -378,7 +470,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { private static class ConstantInfo implements ConstantListener { ConstantInfo() { - this(REACHABLE, null); + this(0, null); } ConstantInfo(int flags) { @@ -488,7 +580,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { public void handleOpcode(StackLocalInfo info, Identifier fieldListener) { Instruction instr = info.instr; - constInfos.put(instr, unknownConstInfo); + info.constInfo = unknownConstInfo; int opcode = instr.getOpcode(); Handler[] handlers = bytecode.getExceptionHandlers(); @@ -519,11 +611,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { System.err.println(instr); } if (result.value != ConstValue.VOLATILE) { - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = result.value; - result.addConstantListener(shortInfo); + info.constInfo = new ConstantInfo(CONSTANT, result.value); + result.addConstantListener(info.constInfo); } mergeInfo(instr.getNextByAddr(), info.poppush(0, result) @@ -573,8 +662,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { break; } case opc_istore: case opc_fstore: case opc_astore: { + result = info.getStack(1); + if (result.value instanceof JSRTargetInfo) + info.constInfo.flags |= RETASTORE; mergeInfo(instr.getNextByAddr(), - info.pop(1).setLocal(instr.getLocalSlot(), info.getStack(1))); + info.pop(1).setLocal(instr.getLocalSlot(), result)); break; } case opc_lstore: case opc_dstore: { @@ -590,8 +682,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { mergeInfo(instr.getNextByAddr(), info.pop(2+size)); break; } - case opc_pop: case opc_pop2: - mergeInfo(instr.getNextByAddr(), info.pop(opcode - (opc_pop - 1))); + case opc_pop: + mergeInfo(instr.getNextByAddr(), info.pop(1)); + break; + case opc_pop2: + mergeInfo(instr.getNextByAddr(), info.pop(2)); break; case opc_dup: case opc_dup_x1: case opc_dup_x2: @@ -763,12 +858,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { default: throw new jode.AssertError("Can't happen."); } - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = newValue; + info.constInfo = new ConstantInfo(CONSTANT, newValue); result = new ConstValue(newValue); - result.addConstantListener(shortInfo); + result.addConstantListener(info.constInfo); value1.addConstantListener(result); value2.addConstantListener(result); } else @@ -801,12 +893,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { default: throw new jode.AssertError("Can't happen."); } - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = newValue; + info.constInfo = new ConstantInfo(CONSTANT, newValue); result = new ConstValue(newValue); - result.addConstantListener(shortInfo); + result.addConstantListener(info.constInfo); value.addConstantListener(result); } else result = unknownValue[size-1]; @@ -857,12 +946,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { default: throw new jode.AssertError("Can't happen."); } - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = newValue; + info.constInfo = new ConstantInfo(CONSTANT, newValue); result = new ConstValue(newValue); - result.addConstantListener(shortInfo); + result.addConstantListener(info.constInfo); value1.addConstantListener(result); value2.addConstantListener(result); } else @@ -907,12 +993,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { default: throw new jode.AssertError("Can't happen."); } - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = newVal; + info.constInfo = new ConstantInfo(CONSTANT, newVal); result = new ConstValue(newVal); - result.addConstantListener(shortInfo); + result.addConstantListener(info.constInfo); stack.addConstantListener(result); } else { switch (opcode) { @@ -942,12 +1025,10 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { val = (short) val; break; } - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = new Integer(val); - result = new ConstValue(shortInfo.constant); - stack.addConstantListener(shortInfo); + Integer newVal = new Integer(val); + info.constInfo = new ConstantInfo(CONSTANT, newVal); + result = new ConstValue(newVal); + stack.addConstantListener(info.constInfo); stack.addConstantListener(result); } else result = unknownValue[0]; @@ -962,13 +1043,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { && val2.value != ConstValue.VOLATILE) { long value1 = ((Long) val1.value).longValue(); long value2 = ((Long) val1.value).longValue(); - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = new Integer(value1 == value2 ? 0 - : value1 < value2 ? -1 : 1); - result = new ConstValue(shortInfo.constant); - result.addConstantListener(shortInfo); + Integer newVal = new Integer(value1 == value2 ? 0 + : value1 < value2 ? -1 : 1); + info.constInfo = new ConstantInfo(CONSTANT, newVal); + result = new ConstValue(newVal); + result.addConstantListener(info.constInfo); val1.addConstantListener(result); val2.addConstantListener(result); } else @@ -983,16 +1062,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { && val2.value != ConstValue.VOLATILE) { float value1 = ((Float) val1.value).floatValue(); float value2 = ((Float) val1.value).floatValue(); - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = new Integer + Integer newVal = new Integer (value1 == value2 ? 0 : ( opcode == opc_fcmpg ? (value1 < value2 ? -1 : 1) : (value1 > value2 ? 1 : -1))); - result = new ConstValue(shortInfo.constant); - result.addConstantListener(shortInfo); + info.constInfo = new ConstantInfo(CONSTANT, newVal); + result = new ConstValue(newVal); + result.addConstantListener(info.constInfo); val1.addConstantListener(result); val2.addConstantListener(result); } else @@ -1007,16 +1084,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { && val2.value != ConstValue.VOLATILE) { double value1 = ((Double) val1.value).doubleValue(); double value2 = ((Double) val1.value).doubleValue(); - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANT; - shortInfo.constant = new Integer + Integer newVal = new Integer (value1 == value2 ? 0 : ( opcode == opc_dcmpg ? (value1 < value2 ? -1 : 1) : (value1 > value2 ? 1 : -1))); - result = new ConstValue(shortInfo.constant); - result.addConstantListener(shortInfo); + info.constInfo = new ConstantInfo(CONSTANT, newVal); + result = new ConstValue(newVal); + result.addConstantListener(info.constInfo); val1.addConstantListener(result); val2.addConstantListener(result); } else @@ -1077,10 +1152,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { if ((opc_mask & (1< opc_ldc2_w) { @@ -1539,9 +1622,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { + " with goto " + pc.getAddr()); while (iter.hasNext()) { ConstantInfo nextinfo = (ConstantInfo) - constInfos.get((Instruction) iter.next()); - if (nextinfo != null - && (nextinfo.flags & REACHABLE) != 0) { + ((Instruction) iter.next()).getTmpInfo(); + if (nextinfo != null) { Instruction nextInstr = (Instruction) iter.previous(); if (pc != nextInstr) appendJump(iter, pc); @@ -1558,6 +1640,21 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { iter.remove(); break; + case opc_jsr: + ConstantInfo jsrinfo = (ConstantInfo) + instr.getSingleSucc().getTmpInfo(); + if ((jsrinfo.flags & RETURNINGJSR) != 0) + /* A normal jsr, don't change it */ + break; + + /* This means, the jsr will never return. We + * replace it with a goto, the jsr will transform + * itself to remove the astore operation. + */ + Instruction gotoInstr = new Instruction(opc_goto); + gotoInstr.setSuccs(instr.getSingleSucc()); + iter.set(gotoInstr); + /* fall through */ case opc_goto: case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: @@ -1570,18 +1667,22 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { while (iter.hasNext()) { ConstantInfo nextinfo = (ConstantInfo) - constInfos.get((Instruction) iter.next()); + ((Instruction) iter.next()).getTmpInfo(); if (nextinfo != null - && (nextinfo.flags & REACHABLE) != 0) { + && ((nextinfo.flags & (RETURNINGJSR | RETASTORE)) + != RETASTORE)) { + Instruction nextInstr = (Instruction) iter.previous(); if (instr.getSingleSucc() == nextInstr) { + /* put iter in sane state */ iter.previous(); + iter.next(); replaceWith(iter, instr, null); } break; } - /* Next instruction can't be reached logically */ + /* Next instruction can be removed */ iter.remove(); } break;