From c3ead8b0847c4b729ce31ab25f413e8d55b9d3f4 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 20 Jul 1999 16:06:47 +0000 Subject: [PATCH] instructions now collectionified Use listIterator to manipulate bytecode Some bug fixes More use of TypeSignature, and prevent using of jode.type.Type git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1097 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/obfuscator/ClassBundle.java.in | 154 +++++++-- jode/jode/obfuscator/ClassIdentifier.java.in | 34 +- jode/jode/obfuscator/ConstantAnalyzer.java.in | 226 ++++++------- jode/jode/obfuscator/FieldIdentifier.java.in | 24 +- ...lOptimizer.java => LocalOptimizer.java.in} | 97 +++--- ....java => LocalizeFieldTransformer.java.in} | 0 jode/jode/obfuscator/Makefile.am | 1 + jode/jode/obfuscator/MethodIdentifier.java.in | 24 +- .../jode/obfuscator/PackageIdentifier.java.in | 77 +---- jode/jode/obfuscator/RemovePopAnalyzer.java | 262 --------------- .../jode/obfuscator/RemovePopAnalyzer.java.in | 307 ++++++++++++++++++ jode/jode/obfuscator/ScriptParser.java.in | 4 +- ...leAnalyzer.java => SimpleAnalyzer.java.in} | 40 ++- jode/jode/obfuscator/UniqueRenamer.java.in | 1 + 14 files changed, 691 insertions(+), 560 deletions(-) rename jode/jode/obfuscator/{LocalOptimizer.java => LocalOptimizer.java.in} (92%) rename jode/jode/obfuscator/{LocalizeFieldTransformer.java => LocalizeFieldTransformer.java.in} (100%) delete mode 100644 jode/jode/obfuscator/RemovePopAnalyzer.java create mode 100644 jode/jode/obfuscator/RemovePopAnalyzer.java.in rename jode/jode/obfuscator/{SimpleAnalyzer.java => SimpleAnalyzer.java.in} (84%) diff --git a/jode/jode/obfuscator/ClassBundle.java.in b/jode/jode/obfuscator/ClassBundle.java.in index e2e0b28..8aa1f71 100644 --- a/jode/jode/obfuscator/ClassBundle.java.in +++ b/jode/jode/obfuscator/ClassBundle.java.in @@ -99,6 +99,21 @@ public class ClassBundle implements OptionHandler { return; } + if (option.equals("table")) { + if (values.size() != 1) + throw new IllegalArgumentException + ("Only one destination path allowed"); + tableFile = (String) values.iterator().next(); + return; + } + + if (option.equals("revtable")) { + if (values.size() != 1) + throw new IllegalArgumentException + ("Only one destination path allowed"); + toTableFile = (String) values.iterator().next(); + return; + } if (option.equals("strip")) { next_token: for (Iterator iter = values.iterator(); iter.hasNext(); ) { @@ -116,33 +131,72 @@ public class ClassBundle implements OptionHandler { } if (option.equals("load")) { - if (values.size() == 1) - loading = (IdentifierMatcher) values.iterator().next(); - else + if (values.size() == 1) { + Object value = values.iterator().next(); + if (value instanceof String) + loading = new WildCard((String)value); + else + loading = (IdentifierMatcher) value; + } else { + IdentifierMatcher[] matchers + = new IdentifierMatcher[values.size()]; + int j = 0; + for (Iterator i = values.iterator(); i.hasNext(); ) { + Object value = i.next(); + matchers[j++] = (value instanceof String + ? new WildCard((String)value) + : (IdentifierMatcher) value); + } loading = new MultiIdentifierMatcher - (MultiIdentifierMatcher.OR, (IdentifierMatcher[]) - values.toArray(new IdentifierMatcher[values.size()])); + (MultiIdentifierMatcher.OR, matchers); + } return; } if (option.equals("preserve")) { - if (values.size() == 1) - preserving = (IdentifierMatcher) values.iterator().next(); - else + if (values.size() == 1) { + Object value = values.iterator().next(); + if (value instanceof String) + preserving = new WildCard((String)value); + else + preserving = (IdentifierMatcher) value; + } else { + IdentifierMatcher[] matchers + = new IdentifierMatcher[values.size()]; + int j = 0; + for (Iterator i = values.iterator(); i.hasNext(); ) { + Object value = i.next(); + matchers[j++] = (value instanceof String + ? new WildCard((String)value) + : (IdentifierMatcher) value); + } preserving = new MultiIdentifierMatcher - (MultiIdentifierMatcher.OR, (IdentifierMatcher[]) - values.toArray(new IdentifierMatcher[values.size()])); + (MultiIdentifierMatcher.OR, matchers); + } return; } if (option.equals("reach")) { // NOT IMPLEMENTED YET - if (values.size() == 1) - reaching = (IdentifierMatcher) values.iterator().next(); - else + if (values.size() == 1) { + Object value = values.iterator().next(); + if (value instanceof String) + reaching = new WildCard((String)value); + else + reaching = (IdentifierMatcher) value; + } else { + IdentifierMatcher[] matchers + = new IdentifierMatcher[values.size()]; + int j = 0; + for (Iterator i = values.iterator(); i.hasNext(); ) { + Object value = i.next(); + matchers[j++] = (value instanceof String + ? new WildCard((String)value) + : (IdentifierMatcher) value); + } reaching = new MultiIdentifierMatcher - (MultiIdentifierMatcher.OR, (IdentifierMatcher[]) - values.toArray(new IdentifierMatcher[values.size()])); + (MultiIdentifierMatcher.OR, matchers); + } } if (option.equals("pre")) { @@ -228,8 +282,22 @@ public class ClassBundle implements OptionHandler { return ident.getIdentifier(ref.getName(), ref.getType()); } - public void reachableIdentifier(String fqn, boolean isVirtual) { - basePackage.reachableIdentifier(fqn, isVirtual); + public void reachableClass(String clazzName) { + ClassIdentifier ident = getClassIdentifier(clazzName); + if (ident != null) + ident.setReachable(); + } + + public void reachableReference(Reference ref, boolean isVirtual) { + String clName = ref.getClazz(); + if (clName.charAt(0) == '[') + /* Can't represent arrays */ + return; + ClassIdentifier ident = + getClassIdentifier(clName.substring(1, clName.length()-1) + .replace('/','.')); + if (ident != null) + ident.reachableReference(ref, isVirtual); } public void analyzeIdentifier(Identifier ident) { @@ -340,7 +408,7 @@ public class ClassBundle implements OptionHandler { } public Object next() { - return (last++ == 1 ? base : base + last); + return (last++ == 0 ? base : base + last); } public void remove() { @@ -349,24 +417,72 @@ public class ClassBundle implements OptionHandler { }; } }; - + + + Runtime runtime = Runtime.getRuntime(); + long free = runtime.freeMemory(); + long last; + do { + last = free; + runtime.gc(); + runtime.runFinalization(); + free = runtime.freeMemory(); + } while (free < last); + System.err.println("used before: "+(runtime.totalMemory()- free)); + GlobalOptions.err.println("Loading and preserving classes"); + + long time = System.currentTimeMillis(); basePackage.loadMatchingClasses(loading); basePackage.applyPreserveRule(preserving); + System.err.println("Time used: "+(System.currentTimeMillis() - time)); + GlobalOptions.err.println("Computing reachable settings"); + time = System.currentTimeMillis(); analyze(); + System.err.println("Time used: "+(System.currentTimeMillis() - time)); + + free = runtime.freeMemory(); + do { + last = free; + runtime.gc(); + runtime.runFinalization(); + free = runtime.freeMemory(); + } while (free < last); + System.err.println("used after analyze: " + + (runtime.totalMemory() - free)); GlobalOptions.err.println("Renaming methods"); + time = System.currentTimeMillis(); if (tableFile != null) readTable(); buildTable(renamer); if (toTableFile != null) writeTable(); + System.err.println("Time used: "+(System.currentTimeMillis() - time)); GlobalOptions.err.println("Transforming the classes"); + time = System.currentTimeMillis(); doTransformations(); + System.err.println("Time used: "+(System.currentTimeMillis() - time)); + + free = runtime.freeMemory(); + do { + last = free; + runtime.gc(); + runtime.runFinalization(); + free = runtime.freeMemory(); + } while (free < last); + System.err.println("used after transform: " + + (runtime.totalMemory() - free)); + GlobalOptions.err.println("Writing new classes"); + time = System.currentTimeMillis(); storeClasses(); + System.err.println("Time used: "+(System.currentTimeMillis() - time)); } } + + + diff --git a/jode/jode/obfuscator/ClassIdentifier.java.in b/jode/jode/obfuscator/ClassIdentifier.java.in index 5423049..55251c6 100644 --- a/jode/jode/obfuscator/ClassIdentifier.java.in +++ b/jode/jode/obfuscator/ClassIdentifier.java.in @@ -60,10 +60,8 @@ public class ClassIdentifier extends Identifier { public void addSubClass(ClassIdentifier ci) { knownSubClasses.add(ci); - for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) { - String[] method = (String[]) i.next(); - ci.reachableIdentifier(method[0], method[1], true); - } + for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) + ci.reachableReference((Reference) i.next(), true); } private FieldIdentifier findField(String name, String typeSig) { @@ -86,13 +84,12 @@ public class ClassIdentifier extends Identifier { return null; } - public void reachableIdentifier(String name, String typeSig, - boolean isVirtual) { + public void reachableReference(Reference ref, boolean isVirtual) { boolean found = false; for (Iterator i = getChilds(); i.hasNext(); ) { Identifier ident = (Identifier) i.next(); - if (name.equals(ident.getName()) - && typeSig.equals(ident.getType())) { + if (ref.getName().equals(ident.getName()) + && ref.getType().equals(ident.getType())) { ident.setReachable(); found = true; } @@ -108,14 +105,21 @@ public class ClassIdentifier extends Identifier { ClassIdentifier superIdent = Main.getClassBundle() .getClassIdentifier(info.getSuperclass().getName()); if (superIdent != null) - superIdent.reachableIdentifier(name, typeSig, false); + superIdent.reachableReference(ref, false); } if (isVirtual) { + for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) { + Reference prevRef = (Reference) i.next(); + if (prevRef.getName().equals(ref.getName()) + && prevRef.getType().equals(ref.getType())) + // already handled. + return; + } for (Iterator i = knownSubClasses.iterator(); i.hasNext(); ) ((ClassIdentifier)i.next()) - .reachableIdentifier(name, typeSig, false); - virtualReachables.add(new String[] { name, typeSig }); + .reachableReference(ref, false); + virtualReachables.add(ref); } } @@ -308,14 +312,18 @@ public class ClassIdentifier extends Identifier { superident.addSubClass(this); } else { // all virtual methods in superclass are reachable now! + String clazzType = ("L"+superclass.getName().replace('.', '/') + +";").intern(); MethodInfo[] topmethods = superclass.getMethods(); for (int i=0; i< topmethods.length; i++) { int modif = topmethods[i].getModifiers(); if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL) & modif) == 0 && !topmethods[i].getName().equals("")) { - reachableIdentifier - (topmethods[i].getName(), topmethods[i].getType(), + reachableReference + (Reference.getReference(clazzType, + topmethods[i].getName(), + topmethods[i].getType()), true); } } diff --git a/jode/jode/obfuscator/ConstantAnalyzer.java.in b/jode/jode/obfuscator/ConstantAnalyzer.java.in index 3b7f55d..f465aa6 100644 --- a/jode/jode/obfuscator/ConstantAnalyzer.java.in +++ b/jode/jode/obfuscator/ConstantAnalyzer.java.in @@ -38,6 +38,7 @@ import @COLLECTIONS@.Set; import @COLLECTIONS@.HashMap; import @COLLECTIONS@.Map; import @COLLECTIONS@.Iterator; +import @COLLECTIONS@.ListIterator; /** * Analyze the code, assuming every field that is not yet written to @@ -464,13 +465,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { } public void handleReference(Reference ref, boolean isVirtual) { - String clName = ref.getClazz(); - /* Don't have to reach array methods */ - if (clName.charAt(0) != '[') { - clName = clName.substring(1, clName.length()-1).replace('/', '.'); - Main.getClassBundle().reachableIdentifier - (clName+"."+ref.getName()+"."+ref.getType(), isVirtual); - } + Main.getClassBundle().reachableReference(ref, isVirtual); } public void handleClass(String clName) { @@ -479,7 +474,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { i++; if (i < clName.length() && clName.charAt(i) == 'L') { clName = clName.substring(i+1, clName.length()-1); - Main.getClassBundle().reachableIdentifier(clName, false); + Main.getClassBundle().reachableClass(clName); } } @@ -872,7 +867,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { if (local.value != ConstValue.VOLATILE) { result = new ConstValue (new Integer(((Integer)local.value).intValue() - + instr.getIntData())); + + instr.getIncrement())); local.addConstantListener(result); } else result = unknownValue[0]; @@ -1072,7 +1067,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { } if ((opc_mask & (1<= low && value <= low + instr.getSuccs().length - 2) - pc = instr.getSuccs()[value - low]; - else - pc = instr.getSuccs()[instr.getSuccs().length-1]; - ConstantInfo shortInfo = new ConstantInfo(); - constInfos.put(instr, shortInfo); - shortInfo.flags |= CONSTANTFLOW; - shortInfo.constant = pc; - mergeInfo(pc, info.pop(1)); - } else { - for (int i=0; i < instr.getSuccs().length; i++) - mergeInfo(instr.getSuccs()[i], info.pop(1)); - } - break; - } case opc_lookupswitch: { ConstValue stacktop = info.getStack(1); if (stacktop.value != ConstValue.VOLATILE) { @@ -1264,15 +1238,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { constant = false; if (jode.GlobalOptions.verboseLevel > 3) GlobalOptions.err.println("Can't interpret "+ref+": " - + ex.getMessage()); + + ex.getMessage()); /* result is not constant */ } catch (InvocationTargetException ex) { constant = false; if (jode.GlobalOptions.verboseLevel > 3) GlobalOptions.err.println("Method "+ref - +" throwed exception: " - + ex.getTargetException() - .getMessage()); + +" throwed exception: " + + ex.getTargetException()); /* method always throws exception ? */ } } @@ -1333,7 +1306,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { case opc_multianewarray: handleClass(instr.getClazzType()); mergeInfo(instr.getNextByAddr(), - info.poppush(instr.getIntData(), unknownValue[0])); + info.poppush(instr.getDimensions(), unknownValue[0])); break; default: throw new jode.AssertError("Invalid opcode "+opcode); @@ -1342,8 +1315,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { } public void fieldNotConstant(FieldIdentifier fi) { - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.getNextByAddr()) { + for (Iterator iter = bytecode.getInstructions().iterator(); + iter.hasNext(); ) { + Instruction instr = (Instruction) iter.next(); if (instr.getOpcode() == opc_getfield || instr.getOpcode() == opc_getstatic) { Reference ref = instr.getReference(); @@ -1357,8 +1331,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { } public void dumpStackLocalInfo() { - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.getNextByAddr()) { + for (Iterator iter = bytecode.getInstructions().iterator(); + iter.hasNext(); ) { + Instruction instr = (Instruction) iter.next(); StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo(); System.err.println(""+info); System.err.println(instr.getDescription()); @@ -1375,7 +1350,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { StackLocalInfo firstInfo = new StackLocalInfo (bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(), modifiedQueue); - firstInfo.instr = bytecode.getFirstInstr(); + firstInfo.instr = (Instruction) bytecode.getInstructions().get(0); firstInfo.instr.setTmpInfo(firstInfo); modifiedQueue.add(firstInfo); while (!modifiedQueue.isEmpty()) { @@ -1389,35 +1364,43 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { for (int i=0; i< handlers.length; i++) { if (handlers[i].catcher.getTmpInfo() != null && handlers[i].type != null) - Main.getClassBundle().reachableIdentifier(handlers[i].type, false); + Main.getClassBundle().reachableClass(handlers[i].type); } - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.getNextByAddr()) - instr.setTmpInfo(null); + for (Iterator iter = bytecode.getInstructions().iterator(); + iter.hasNext(); ) + ((Instruction) iter.next()).setTmpInfo(null); } - public void insertOnePop(Instruction instr, int count) { - /* Add a goto instruction after this opcode. */ - Instruction pop - = instr.insertInstruction(Instruction.opc_pop - 1 + count); - } - - public void insertPop(Instruction instr) { + public static void replaceWith(ListIterator iter, Instruction instr, + Instruction replacement) { switch(instr.getOpcode()) { + case opc_goto: case opc_ldc: case opc_ldc2_w: case opc_iload: case opc_lload: case opc_fload: case opc_dload: case opc_aload: case opc_getstatic: - break; + if (replacement == null) + iter.remove(); + else + iter.set(replacement); + return; + case opc_ifeq: case opc_ifne: + case opc_iflt: case opc_ifge: + case opc_ifgt: case opc_ifle: + case opc_ifnull: case opc_ifnonnull: case opc_arraylength: case opc_getfield: case opc_i2l: case opc_i2f: case opc_i2d: case opc_f2i: case opc_f2l: case opc_f2d: case opc_i2b: case opc_i2c: case opc_i2s: case opc_ineg: case opc_fneg: - insertOnePop(instr, 1); + iter.set(new Instruction(opc_pop)); break; + case opc_if_icmpeq: case opc_if_icmpne: + case opc_if_icmplt: case opc_if_icmpge: + case opc_if_icmpgt: case opc_if_icmple: + case opc_if_acmpeq: case opc_if_acmpne: case opc_lcmp: case opc_dcmpg: case opc_dcmpl: case opc_ladd: case opc_dadd: @@ -1426,7 +1409,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { case opc_ldiv: case opc_ddiv: case opc_lrem: case opc_drem: case opc_land: case opc_lor : case opc_lxor: - insertOnePop(instr, 2); + iter.set(new Instruction(opc_pop2)); /* fall through */ case opc_fcmpg: case opc_fcmpl: case opc_l2i: case opc_l2f: case opc_l2d: @@ -1442,22 +1425,23 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { case opc_iaload: case opc_laload: case opc_faload: case opc_daload: case opc_aaload: case opc_baload: case opc_caload: case opc_saload: - insertOnePop(instr, 2); + iter.set(new Instruction(opc_pop2)); break; case opc_lshl: case opc_lshr: case opc_lushr: - insertOnePop(instr, 1); - insertOnePop(instr, 2); + iter.set(new Instruction(opc_pop2)); + iter.add(new Instruction(opc_pop)); break; case opc_putstatic: case opc_putfield: if (Type.tType(instr.getReference().getType()) .stackSize() == 2) { - insertOnePop(instr, 2); + iter.set(new Instruction(opc_pop2)); if (instr.getOpcode() == opc_putfield) - insertOnePop(instr, 1); + iter.add(new Instruction(opc_pop)); } else - insertOnePop(instr, (instr.getOpcode() == opc_putfield) ? 2 : 1); + iter.set(new Instruction(instr.getOpcode() == opc_putfield + ? opc_pop2 : opc_pop)); break; case opc_invokespecial: case opc_invokestatic: @@ -1465,34 +1449,52 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { case opc_invokevirtual: { Reference ref = instr.getReference(); MethodType mt = (MethodType) Type.tType(ref.getType()); - for (int i=mt.getParameterTypes().length-1; i >=0; i--) - insertOnePop(instr, mt.getParameterTypes()[i].stackSize()); + Type[] pt = mt.getParameterTypes(); + int arg = 0; if (instr.getOpcode() != opc_invokestatic) - insertOnePop(instr, 1); + iter.set(new Instruction(opc_pop)); + else if (pt.length > 0) { + iter.set(new Instruction(pt[0].stackSize() + opc_pop - 1)); + arg++; + } else { + if (replacement == null) + iter.remove(); + else + iter.set(replacement); + return; + } + + for (int i=arg; i < pt.length; i++) + iter.add(new Instruction(pt[i].stackSize() + opc_pop - 1)); } } + if (replacement != null) + iter.add(replacement); } - public void appendJump(Instruction instr, Instruction dest) { + public void appendJump(ListIterator iter, Instruction dest) { /* Add a goto instruction after this opcode. */ - instr.appendInstruction(Instruction.opc_goto, - new Instruction[] { dest }); + Instruction gotoInstr = new Instruction(Instruction.opc_goto); + gotoInstr.setSuccs(dest); + iter.add(gotoInstr); } public void transformCode(BytecodeInfo bytecode) { - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.getNextByAddr()) { + for (ListIterator iter = bytecode.getInstructions().listIterator(); + iter.hasNext(); ) { + Instruction instr = (Instruction) iter.next(); ConstantInfo info = (ConstantInfo) constInfos.get(instr); if (info == null || (info.flags & REACHABLE) == 0) { /* This instruction can't be reached logically */ - instr.removeInstruction(); + iter.remove(); } else if ((info.flags & CONSTANT) != 0) { - insertPop(instr); if (instr.getOpcode() > opc_ldc2_w) { - instr.replaceInstruction(info.constant instanceof Long - || info.constant instanceof Double - ? opc_ldc2_w : opc_ldc); - instr.setConstant(info.constant); + Instruction ldcInstr + = new Instruction(info.constant instanceof Long + || info.constant instanceof Double + ? opc_ldc2_w : opc_ldc); + ldcInstr.setConstant(info.constant); + replaceWith(iter, instr, ldcInstr); if (GlobalOptions.verboseLevel > 2) GlobalOptions.err.println (bytecode + ": Replacing " + instr @@ -1502,61 +1504,60 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { Instruction pc = (Instruction) info.constant; if (instr.getOpcode() >= opc_if_icmpeq && instr.getOpcode() <= opc_if_acmpne) - instr.replaceInstruction(opc_pop2); + iter.set(new Instruction(opc_pop2)); else - instr.replaceInstruction(opc_pop); + iter.set(new Instruction(opc_pop)); if (GlobalOptions.verboseLevel > 2) GlobalOptions.err.println (bytecode + ": Replacing " + instr + " with goto " + pc.getAddr()); - while (instr.getNextByAddr() != null) { - ConstantInfo nextinfo - = (ConstantInfo) constInfos.get(instr.getNextByAddr()); - if (nextinfo != null && (nextinfo.flags & REACHABLE) != 0) + while (iter.hasNext()) { + ConstantInfo nextinfo = (ConstantInfo) + constInfos.get((Instruction) iter.next()); + if (nextinfo != null + && (nextinfo.flags & REACHABLE) != 0) { + Instruction nextInstr = (Instruction) iter.previous(); + if (pc != nextInstr) + appendJump(iter, pc); break; + } /* Next instruction can't be reached logically */ - instr.getNextByAddr().removeInstruction(); + iter.remove(); } - if (pc != instr.getNextByAddr()) { - appendJump(instr, pc); - instr = instr.getNextByAddr(); - } - } else { int opcode = instr.getOpcode(); switch (opcode) { case opc_nop: - instr.removeInstruction(); + iter.remove(); break; case opc_goto: - while (instr.getNextByAddr() != null) { - ConstantInfo nextinfo - = (ConstantInfo) constInfos.get(instr.getNextByAddr()); - if (nextinfo != null - && (nextinfo.flags & REACHABLE) != 0) - break; - /* Next instruction can't be reached logically */ - instr.getNextByAddr().removeInstruction(); - } - if (instr.getSuccs()[0] == instr.getNextByAddr()) - instr.removeInstruction(); - break; case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: case opc_ifnull: case opc_ifnonnull: - if (instr.getSuccs()[0] == instr.getNextByAddr()) - instr.replaceInstruction(opc_pop); - break; - case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: - if (instr.getSuccs()[0] == instr.getNextByAddr()) - instr.replaceInstruction(opc_pop2); + + while (iter.hasNext()) { + ConstantInfo nextinfo = (ConstantInfo) + constInfos.get((Instruction) iter.next()); + if (nextinfo != null + && (nextinfo.flags & REACHABLE) != 0) { + Instruction nextInstr + = (Instruction) iter.previous(); + if (instr.getSingleSucc() == nextInstr) { + iter.previous(); + replaceWith(iter, instr, null); + } + break; + } + /* Next instruction can't be reached logically */ + iter.remove(); + } break; case opc_putstatic: @@ -1567,8 +1568,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { if (fi != null && (Main.stripping & Main.STRIP_UNREACH) != 0 && !fi.isReachable()) { - insertPop(instr); - instr.removeInstruction(); + replaceWith(iter, instr, null); } break; } diff --git a/jode/jode/obfuscator/FieldIdentifier.java.in b/jode/jode/obfuscator/FieldIdentifier.java.in index 484a826..b17873d 100644 --- a/jode/jode/obfuscator/FieldIdentifier.java.in +++ b/jode/jode/obfuscator/FieldIdentifier.java.in @@ -65,8 +65,8 @@ public class FieldIdentifier extends Identifier{ int index = type.indexOf('L'); if (index != -1) { int end = type.indexOf(';', index); - Main.getClassBundle().reachableIdentifier - (type.substring(index+1, end), false); + Main.getClassBundle().reachableClass + (type.substring(index+1, end).replace('/', '.')); } } @@ -75,11 +75,12 @@ public class FieldIdentifier extends Identifier{ } public String getFullName() { - return clazz.getFullName() + "." + getName(); + return clazz.getFullName() + "." + getName() + "." + getType(); } public String getFullAlias() { - return clazz.getFullAlias() + "." + getAlias(); + return clazz.getFullAlias() + "." + getAlias() + "." + + Main.getClassBundle().getTypeAlias(getType()); } public String getName() { @@ -120,20 +121,7 @@ public class FieldIdentifier extends Identifier{ } public String toString() { - return "FieldIdentifier "+getFullName()+"."+getType(); - } - - public void readTable(Map table) { - String alias = (String) table.get(getFullName() + "." + getType()); - if (alias == null) - alias = (String) table.get(getFullName()); - if (alias != null) - setAlias(alias); - } - - public void writeTable(Map table) { - table.put(getFullAlias() + "." - + Main.getClassBundle().getTypeAlias(getType()), getName()); + return "FieldIdentifier "+getFullName(); } public boolean conflicting(String newAlias) { diff --git a/jode/jode/obfuscator/LocalOptimizer.java b/jode/jode/obfuscator/LocalOptimizer.java.in similarity index 92% rename from jode/jode/obfuscator/LocalOptimizer.java rename to jode/jode/obfuscator/LocalOptimizer.java.in index be7dc7f..3d7bddc 100644 --- a/jode/jode/obfuscator/LocalOptimizer.java +++ b/jode/jode/obfuscator/LocalOptimizer.java.in @@ -20,10 +20,12 @@ package jode.obfuscator; import java.util.*; import jode.bytecode.*; -import jode.type.Type; import jode.AssertError; import jode.GlobalOptions; +import @COLLECTIONS@.Iterator; +import @COLLECTIONS@.ListIterator; + /** * This class takes some bytecode and tries to minimize the number * of locals used. It will also remove unnecessary stores. @@ -221,14 +223,12 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { BitSet mergeSet, boolean inverted) { InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr); int omitLocal = -1; - if (preInstr.getLocalSlot() != -1 - && preInstr.getOpcode() >= opc_istore + if (preInstr.getOpcode() >= opc_istore && preInstr.getOpcode() <= opc_astore) { /* This is a store */ omitLocal = preInstr.getLocalSlot(); - if (info.nextReads[preInstr.getLocalSlot()] != null) - preInfo.local.combineInto - (info.nextReads[preInstr.getLocalSlot()].local); + if (info.nextReads[omitLocal] != null) + preInfo.local.combineInto(info.nextReads[omitLocal].local); } for (int i=0; i < maxlocals; i++) { if (info.nextReads[i] != null && i != omitLocal @@ -270,10 +270,12 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt, Instruction instr) { - int addr = instr.getAddr(); + int addr; if (instr.getOpcode() >= opc_istore && instr.getOpcode() <= opc_astore) - addr += instr.getLength(); + addr = instr.getNextAddr(); + else + addr = instr.getAddr(); return findLVTEntry(lvt, instr.getLocalSlot(), addr); } @@ -286,11 +288,9 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { /* Initialize paramLocals */ { - int paramCount = bc.getMethodInfo().isStatic() ? 0 : 1; - Type[] paramTypes = - Type.tMethod(bc.getMethodInfo().getType()).getParameterTypes(); - for (int i = paramTypes.length; i-- > 0;) - paramCount += paramTypes[i].stackSize(); + String methodType = bc.getMethodInfo().getType(); + int paramCount = (bc.getMethodInfo().isStatic() ? 0 : 1) + + TypeSignature.getArgumentSize(methodType); paramLocals = new LocalInfo[paramCount]; int slot = 0; if (!bc.getMethodInfo().isStatic()) { @@ -305,7 +305,10 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { local.size = 1; paramLocals[slot++] = local; } - for (int i = 0; i< paramTypes.length; i++) { + int pos = 1; + while (pos < methodType.length() + && methodType.charAt(pos) != ')') { + LocalInfo local = new LocalInfo(); if (lvt != null) { LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0); @@ -313,8 +316,11 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { local.name = lvi.name; } } - local.type = paramTypes[i].getTypeSignature(); - local.size = paramTypes[i].stackSize(); + + int start = pos; + pos = TypeSignature.skipType(methodType, pos); + local.type = methodType.substring(start, pos); + local.size = TypeSignature.getTypeSize(local.type); paramLocals[slot] = local; slot += local.size; } @@ -326,12 +332,13 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { instrInfos = new Hashtable(); { InstrInfo info = firstInfo = new InstrInfo(); - Instruction instr = bc.getFirstInstr(); + Iterator i = bc.getInstructions().iterator(); while (true) { + Instruction instr = (Instruction) i.next(); instrInfos.put(instr, info); info.instr = instr; info.nextReads = new InstrInfo[maxlocals]; - if (instr.getLocalSlot() != -1) { + if (instr.hasLocalSlot()) { info.local = new LocalInfo(info); if (lvt != null) { LocalVariableInfo lvi = findLVTEntry(lvt, instr); @@ -364,7 +371,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { //case opc_istore: case opc_fstore: case opc_astore: } } - if ((instr = instr.getNextByAddr()) == null) + if (!i.hasNext()) break; info = info.nextInfo = new InstrInfo(); } @@ -377,16 +384,17 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { Instruction instr = info.instr; /* Mark the local as used in all ret instructions */ - if (instr.getLocalSlot() != -1) { + if (instr.hasLocalSlot()) { + int slot = instr.getLocalSlot(); for (int i=0; i< maxlocals; i++) { InstrInfo retInfo = info.nextReads[i]; - if (retInfo != null && retInfo.instr.getOpcode() == opc_ret - && !retInfo.usedBySub.get(instr.getLocalSlot())) { - retInfo.usedBySub.set(instr.getLocalSlot()); + if (retInfo != null + && retInfo.instr.getOpcode() == opc_ret + && !retInfo.usedBySub.get(slot)) { + retInfo.usedBySub.set(slot); if (retInfo.jsrTargetInfo != null) changedInfos.push(retInfo.jsrTargetInfo); } - } } @@ -397,7 +405,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { * corresponding ret. */ InstrInfo jsrInfo = - (InstrInfo) instrInfos.get(prevInstr.getSuccs()[0]); + (InstrInfo) instrInfos.get(prevInstr.getSingleSucc()); if (jsrInfo.retInfo != null) { /* Now promote reads that are modified by the * subroutine to the ret, and those that are not @@ -426,8 +434,8 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { * local. */ throw new AssertError("Non standard jsr"); } - InstrInfo retInfo - = info.nextInfo.nextReads[info.instr.getLocalSlot()]; + InstrInfo retInfo = info.nextInfo.nextReads + [info.instr.getLocalSlot()]; if (retInfo != null) { if (retInfo.instr.getOpcode() != opc_ret) @@ -481,21 +489,21 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { } public void stripLocals() { + ListIterator iter = bc.getInstructions().listIterator(); for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { + Instruction instr = (Instruction) iter.next(); if (info.local != null && info.local.usingInstrs.size() == 1) { /* If this is a store, whose value is never read; it can * be removed, i.e replaced by a pop. */ - switch (info.instr.getOpcode()) { + switch (instr.getOpcode()) { case opc_istore: case opc_fstore: case opc_astore: - info.local = null; - info.instr.replaceInstruction(opc_pop); + iter.set(new Instruction(opc_pop)); break; case opc_lstore: case opc_dstore: - info.local = null; - info.instr.replaceInstruction(opc_pop); + iter.set(new Instruction(opc_pop2)); break; default: } @@ -568,8 +576,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { /* Now calculate the conflict settings. */ for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { - if (info.instr.getLocalSlot() != -1 - && info.instr.getOpcode() >= BytecodeInfo.opc_istore + if (info.instr.getOpcode() >= BytecodeInfo.opc_istore && info.instr.getOpcode() <= BytecodeInfo.opc_astore) { /* This is a store. It conflicts with every local, whose * value will be read without write. @@ -692,13 +699,14 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { InstrInfo info = (InstrInfo) changedInfo.pop(); Instruction instr = info.instr; LocalInfo[] newLife = info.lifeLocals; - if (instr.getLocalSlot() != -1) { + if (instr.hasLocalSlot()) { + int slot = instr.getLocalSlot(); LocalInfo instrLocal = info.local.getReal(); newLife = (LocalInfo[]) newLife.clone(); - newLife[instr.getLocalSlot()] = instrLocal; + newLife[slot] = instrLocal; if (instrLocal.name != null) { for (int j=0; j< newLife.length; j++) { - if (j != instr.getLocalSlot() + if (j != slot && newLife[j] != null && instrLocal.name.equals(newLife[j].name)) { /* This local changed the slot. */ @@ -713,17 +721,18 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { if (promoteLifeLocals(newLife, nextInfo)) changedInfo.push(nextInfo); } - if (instr.getSuccs() != null) { - for (int i = 0; i < instr.getSuccs().length; i++) { + if (instr.hasSuccs()) { + Instruction[] succs = instr.getSuccs(); + for (int i = 0; i < succs.length; i++) { InstrInfo nextInfo - = (InstrInfo) instrInfos.get(instr.getSuccs()[i]); + = (InstrInfo) instrInfos.get(succs[i]); if (promoteLifeLocals(newLife, nextInfo)) changedInfo.push(nextInfo); } } for (int i=0; i < handlers.length; i++) { - if (handlers[i].start.getAddr() <= instr.getAddr() - && handlers[i].end.getAddr() >= instr.getAddr()) { + if (handlers[i].start.compareTo(instr) <= 0 + && handlers[i].end.compareTo(instr) >= 0) { InstrInfo nextInfo = (InstrInfo) instrInfos.get(handlers[i].catcher); if (promoteLifeLocals(newLife, nextInfo)) @@ -734,7 +743,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { if (info.instr.getOpcode() == opc_jsr) { /* On a jsr we do a special merge */ - Instruction jsrTargetInstr = info.instr.getSuccs()[0]; + Instruction jsrTargetInstr = info.instr.getSingleSucc(); InstrInfo jsrTargetInfo = (InstrInfo) instrInfos.get(jsrTargetInstr); InstrInfo retInfo = jsrTargetInfo.retInfo; @@ -783,7 +792,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer { lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */ lvi[i].type = Main.getClassBundle() .getTypeAlias(currentLocal[i].type); - lvi[i].start = bc.getFirstInstr(); + lvi[i].start = (Instruction) bc.getInstructions().get(0); lvi[i].slot = i; } } diff --git a/jode/jode/obfuscator/LocalizeFieldTransformer.java b/jode/jode/obfuscator/LocalizeFieldTransformer.java.in similarity index 100% rename from jode/jode/obfuscator/LocalizeFieldTransformer.java rename to jode/jode/obfuscator/LocalizeFieldTransformer.java.in diff --git a/jode/jode/obfuscator/Makefile.am b/jode/jode/obfuscator/Makefile.am index 0c9adfd..d63c77a 100644 --- a/jode/jode/obfuscator/Makefile.am +++ b/jode/jode/obfuscator/Makefile.am @@ -34,6 +34,7 @@ MY_JAVA_FILES = \ SimpleAnalyzer.java \ StrongRenamer.java \ TranslationTable.java \ + UniqueRenamer.java \ WildCard.java # LocalizeFieldTransformer.java diff --git a/jode/jode/obfuscator/MethodIdentifier.java.in b/jode/jode/obfuscator/MethodIdentifier.java.in index d4ce75a..c482690 100644 --- a/jode/jode/obfuscator/MethodIdentifier.java.in +++ b/jode/jode/obfuscator/MethodIdentifier.java.in @@ -88,9 +88,8 @@ public class MethodIdentifier extends Identifier implements Opcodes { int index = type.indexOf('L'); while (index != -1) { int end = type.indexOf(';', index); - Main.getClassBundle() - .reachableIdentifier(type.substring(index+1, end) - , false); + Main.getClassBundle().reachableClass + (type.substring(index+1, end).replace('/', '.')); index = type.indexOf('L', end); } @@ -98,7 +97,7 @@ public class MethodIdentifier extends Identifier implements Opcodes { if (exceptions != null) { for (int i=0; i< exceptions.length; i++) Main.getClassBundle() - .reachableIdentifier(exceptions[i], false); + .reachableClass(exceptions[i]); } BytecodeInfo code = info.getBytecode(); @@ -106,14 +105,6 @@ public class MethodIdentifier extends Identifier implements Opcodes { codeAnalyzer.analyzeCode(this, code); } - public void readTable(Map table) { - setAlias((String) table.get(getFullName() + "." + getType())); - } - - public void writeTable(Map table) { - table.put(getFullAlias(), getName()); - } - public Identifier getParent() { return clazz; } @@ -140,7 +131,7 @@ public class MethodIdentifier extends Identifier implements Opcodes { } public String toString() { - return "MethodIdentifier "+getFullName()+"."+getType(); + return "MethodIdentifier "+getFullName(); } public boolean hasGlobalSideEffects() { @@ -187,9 +178,10 @@ public class MethodIdentifier extends Identifier implements Opcodes { ex.printStackTrace(GlobalOptions.err); bytecode.dumpCode(GlobalOptions.err); } - - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.getNextByAddr()) { + + for (Iterator iter = bytecode.getInstructions().iterator(); + iter.hasNext(); ) { + Instruction instr = (Instruction) iter.next(); switch (instr.getOpcode()) { case opc_invokespecial: case opc_invokestatic: diff --git a/jode/jode/obfuscator/PackageIdentifier.java.in b/jode/jode/obfuscator/PackageIdentifier.java.in index 95bf577..78c1f71 100644 --- a/jode/jode/obfuscator/PackageIdentifier.java.in +++ b/jode/jode/obfuscator/PackageIdentifier.java.in @@ -64,44 +64,32 @@ public class PackageIdentifier extends Identifier { return; loadOnDemand = true; if ((Main.stripping & Main.STRIP_UNREACH) == 0) { + String fullname = getFullName(); + if (fullname.length() > 0) + fullname += "."; + // Load all classes and packages now, so they don't get stripped - Vector v = new Vector(); Enumeration enum = ClassInfo.getClassesAndPackages(getFullName()); while (enum.hasMoreElements()) { - //insert sorted and remove double elements; - String subclazz = (String)enum.nextElement(); - for (int i=0; ; i++) { - if (i == v.size()) { - v.addElement(subclazz); - break; - } - int compare = subclazz.compareTo((String)v.elementAt(i)); - if (compare < 0) { - v.insertElementAt(subclazz, i); - break; - } else if (compare == 0) - break; - } - } - enum = v.elements(); - while (enum.hasMoreElements()) { - String subclazz = (String) enum.nextElement(); - String fullname = getFullName(); - fullname = (fullname.length() > 0) - ? fullname + "."+ subclazz - : subclazz; - if (ClassInfo.isPackage(fullname)) { + String subclazz = ((String)enum.nextElement()).intern(); + if (loadedClasses.containsKey(subclazz)) + continue; + String subFull = fullname + subclazz; + + if (ClassInfo.isPackage(subFull)) { PackageIdentifier ident = new PackageIdentifier (bundle, this, subclazz); loadedClasses.put(subclazz, ident); ident.setLoadOnDemand(); } else { - Identifier ident = new ClassIdentifier - (this, subclazz, ClassInfo.forName(fullname)); + ClassIdentifier ident = new ClassIdentifier + (this, subclazz, ClassInfo.forName(subFull)); + + if (GlobalOptions.verboseLevel > 1) + GlobalOptions.err.println("preloading Class " + + subFull); loadedClasses.put(subclazz, ident); - if (GlobalOptions.verboseLevel > 0) - GlobalOptions.err.println("preloading "+ident); ((ClassIdentifier) ident).initClass(); } } @@ -184,6 +172,7 @@ public class PackageIdentifier extends Identifier { if (component != null) { Identifier ident = (Identifier) loadedClasses.get(component); if (ident == null) { + component = component.intern(); String fullname = getFullName(); fullname = (fullname.length() > 0) ? fullname + "." + component @@ -227,7 +216,7 @@ public class PackageIdentifier extends Identifier { Enumeration enum = ClassInfo.getClassesAndPackages(getFullName()); while (enum.hasMoreElements()) { - String subclazz = (String)enum.nextElement(); + String subclazz = ((String)enum.nextElement()).intern(); if (loadedClasses.containsKey(subclazz)) continue; String subFull = fullname + subclazz; @@ -276,36 +265,6 @@ public class PackageIdentifier extends Identifier { loadMatchingClasses(preserveRule); super.applyPreserveRule(preserveRule); } - - public void reachableIdentifier(String fqn, boolean isVirtual) { - int index = fqn.indexOf('.'); - String component = index == -1 ? fqn : fqn.substring(0, index); - Identifier ident = getIdentifier(component); - if (ident == null) - return; - - if (index == -1) { - ident.setReachable(); - return; - } - - if (ident instanceof PackageIdentifier) - ((PackageIdentifier) ident).reachableIdentifier - (fqn.substring(index+1), isVirtual); - else { - String method = fqn.substring(index+1); - index = method.indexOf('.'); - if (index == -1) { - ((ClassIdentifier) ident).reachableIdentifier - (method, null, isVirtual); - } else { - ((ClassIdentifier) ident).reachableIdentifier - (method.substring(0, index), method.substring(index+1), - isVirtual); - } - } - } - // public void preserveMatchingIdentifier(IdentifierMatcher matcher) { // String component = matcher.getNextComponent(getFullName()); // if (component != null) { diff --git a/jode/jode/obfuscator/RemovePopAnalyzer.java b/jode/jode/obfuscator/RemovePopAnalyzer.java deleted file mode 100644 index 0b7d2b4..0000000 --- a/jode/jode/obfuscator/RemovePopAnalyzer.java +++ /dev/null @@ -1,262 +0,0 @@ -/* RemovePopAnalyzer Copyright (C) 1999 Jochen Hoenicke. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id$ - */ - -package jode.obfuscator; -import jode.bytecode.*; -import jode.AssertError; -import jode.GlobalOptions; - -public class RemovePopAnalyzer implements CodeTransformer, Opcodes { - public RemovePopAnalyzer() { - } - - class PopInfo { - int firstPop = 0; - int[] pops; - Instruction nextInstr; - } - - static Instruction shrinkPop(Instruction popInstr, int amount) { - int newPop = popInstr.getOpcode() - (opc_pop-1) - amount; - if (newPop < 0) - throw new jode.AssertError("pop1 on long or double"); - if (newPop == 0) { - Instruction nextInstr = popInstr.getNextByAddr(); - popInstr.removeInstruction(); - return nextInstr; - } - popInstr.replaceInstruction(opc_pop - 1 + newPop); - return popInstr; - } - - public void transformCode(BytecodeInfo bytecode) { - int poppush[] = new int[2]; - Instruction instr = bytecode.getFirstInstr(); - while (instr != null) { - switch (instr.getOpcode()) { - case opc_nop: { - Instruction nextInstr = instr.getNextByAddr(); - instr.removeInstruction(); - instr = nextInstr; - continue; - } - case opc_pop: - case opc_pop2: { - /* find push instruction */ - int count = 0; - Instruction pushInstr = instr; - while (true) { - if (pushInstr.getPreds() != null) { - pushInstr = null; - break; - } - pushInstr = pushInstr.getPrevByAddr(); - if (pushInstr == null - || pushInstr.getSuccs() != null - || pushInstr.doesAlwaysJump()) { - pushInstr = null; - break; - } - pushInstr.getStackPopPush(poppush); - if (count < poppush[1]) - break; - count += poppush[0] - poppush[1]; - } - int opcode = pushInstr == null ? -1 : pushInstr.getOpcode(); - - if (count > 0) { - /* If this is a dup and the instruction popped is the - * duplicated element, remove the dup - */ - if (count <= 2 && opcode == (opc_dup + count - 1)) { - pushInstr.removeInstruction(); - instr = shrinkPop(instr, 1); - continue; - } - - if (instr.getOpcode() == opc_pop2 - && count > 1 && count <= 3 - && opcode == (opc_dup2 + count-2)) { - pushInstr.removeInstruction(); - instr = shrinkPop(instr, 2); - continue; - } - /* Otherwise popping is not possible */ - opcode = -1; - } - switch (opcode) { - case opc_ldc2_w: - case opc_lload: case opc_dload: - pushInstr.removeInstruction(); - instr = shrinkPop(instr, 2); - continue; - case opc_ldc: - case opc_iload: case opc_fload: case opc_aload: - case opc_dup: - case opc_new: - pushInstr.removeInstruction(); - instr = shrinkPop(instr, 1); - continue; - case opc_iaload: case opc_faload: case opc_aaload: - case opc_baload: case opc_caload: case opc_saload: - /* We have to pop one entry more. */ - pushInstr.replaceInstruction(opc_pop); - instr = pushInstr; - continue; - - case opc_dup_x1: - pushInstr.replaceInstruction(opc_swap); - instr = shrinkPop(instr, 1); - continue; - case opc_dup2: - if (instr.getOpcode() == opc_pop2) { - pushInstr.removeInstruction(); - instr = shrinkPop(instr, 2); - } - continue; - - case opc_lneg: case opc_dneg: - case opc_l2d: case opc_d2l: - case opc_laload: case opc_daload: - if (instr.getOpcode() != opc_pop2) - break; - /* fall through */ - case opc_ineg: case opc_fneg: - case opc_i2f: case opc_f2i: - case opc_i2b: case opc_i2c: case opc_i2s: - case opc_newarray: case opc_anewarray: - case opc_arraylength: - case opc_instanceof: - pushInstr.removeInstruction(); - continue; - - case opc_iadd: case opc_fadd: - case opc_isub: case opc_fsub: - case opc_imul: case opc_fmul: - case opc_idiv: case opc_fdiv: - case opc_irem: case opc_frem: - case opc_iand: case opc_ior : case opc_ixor: - case opc_ishl: case opc_ishr: case opc_iushr: - case opc_fcmpl: case opc_fcmpg: - case opc_l2i: case opc_l2f: - case opc_d2i: case opc_d2f: - pushInstr.replaceInstruction(opc_pop2); - shrinkPop(instr, 1); - instr = pushInstr; - continue; - case opc_ladd: case opc_dadd: - case opc_lsub: case opc_dsub: - case opc_lmul: case opc_dmul: - case opc_ldiv: case opc_ddiv: - case opc_lrem: case opc_drem: - case opc_land: case opc_lor : case opc_lxor: - if (instr.getOpcode() != opc_pop2) - break; - pushInstr.replaceInstruction(opc_pop2); - instr = pushInstr; - continue; - case opc_lshl: case opc_lshr: case opc_lushr: - if (instr.getOpcode() != opc_pop2) - break; - pushInstr.replaceInstruction(opc_pop); - instr = pushInstr; - continue; - - case opc_i2l: case opc_i2d: - case opc_f2l: case opc_f2d: - if (instr.getOpcode() != opc_pop2) - break; - pushInstr.removeInstruction(); - instr.replaceInstruction(opc_pop); - continue; - - case opc_lcmp: - case opc_dcmpl: case opc_dcmpg: - pushInstr.replaceInstruction(opc_pop2); - if (instr.getOpcode() == opc_pop) - instr.replaceInstruction(opc_pop2); - else { - instr.appendInstruction(opc_pop); - } - instr = pushInstr; - continue; - - case opc_getstatic: - case opc_getfield: { - Reference ref = pushInstr.getReference(); - int size = TypeSignature.getTypeSize(ref.getType()); - if (pushInstr.getOpcode() == opc_getfield) - size--; - pushInstr.removeInstruction(); - if (size > 0) - instr = shrinkPop(instr, size); - continue; - } - - case opc_multianewarray: { - int dims = pushInstr.getIntData(); - pushInstr.removeInstruction(); - if (dims == 0) - instr = shrinkPop(instr, 1); - else { - dims--; - while (dims > 0) { - instr = instr.insertInstruction(opc_pop); - dims--; - } - } - continue; - } - - case opc_invokevirtual: - case opc_invokespecial: - case opc_invokestatic: - case opc_invokeinterface: - if (TypeSignature.getReturnSize - (pushInstr.getReference().getType()) != 1) - break; - /* fall through */ - case opc_checkcast: - case -1: - if (instr.getOpcode() == opc_pop2) { - /* This is/may be a double pop on a single value - * split it and continue with second half - */ - instr.replaceInstruction(opc_pop); - instr = instr.appendInstruction(opc_pop); - continue; - } - } - if (instr.getOpcode() == opc_pop - && instr.getPreds() == null - && instr.getPrevByAddr().getOpcode() == opc_pop) { - /* merge two single pops together. */ - instr.getPrevByAddr().removeInstruction(); - instr.replaceInstruction(opc_pop2); - } - /* Cant do anything with this pop */ - } - /* fall through */ - default: - instr = instr.getNextByAddr(); - continue; - } - } - } -} diff --git a/jode/jode/obfuscator/RemovePopAnalyzer.java.in b/jode/jode/obfuscator/RemovePopAnalyzer.java.in new file mode 100644 index 0000000..cab6778 --- /dev/null +++ b/jode/jode/obfuscator/RemovePopAnalyzer.java.in @@ -0,0 +1,307 @@ +/* RemovePopAnalyzer Copyright (C) 1999 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +package jode.obfuscator; +import jode.bytecode.*; +import jode.AssertError; +import jode.GlobalOptions; + +import @COLLECTIONS@.ListIterator; + +public class RemovePopAnalyzer implements CodeTransformer, Opcodes { + public RemovePopAnalyzer() { + } + + public void transformCode(BytecodeInfo bytecode) { + int poppush[] = new int[2]; + ListIterator iter = bytecode.getInstructions().listIterator(); + next_pop: + while (iter.hasNext()) { + Instruction popInstr = (Instruction) iter.next(); + boolean isPop2 = false; + switch (popInstr.getOpcode()) { + case opc_nop: { + iter.remove(); + continue; + } + + case opc_pop2: + isPop2 = true; + case opc_pop: + if (popInstr.getPreds() != null) + // Can't handle pop with multiple predecessors + continue next_pop; + Handler[] handlers = bytecode.getExceptionHandlers(); + for (int i=0; i < handlers.length; i++) + if (handlers[i].catcher == popInstr) + continue next_pop; + + // remove pop, we will insert it again if something + // bad happened. + iter.remove(); + + // remember position of pop, so we can insert it again. + Instruction popPrevious = (Instruction) iter.previous(); + Instruction instr = popPrevious; + int count = 0; + while (true) { + if (instr.getSuccs() != null + || instr.doesAlwaysJump()) { + instr = null; + break; + } + instr.getStackPopPush(poppush); + + if (count < poppush[1]) { + if (count == 0) + break; + + int opcode = instr.getOpcode(); + /* If this is a dup and the instruction popped is the + * duplicated element, remove the dup and the pop + */ + if (count <= 3 && opcode == (opc_dup + count - 1)) { + iter.remove(); + if (!isPop2) + continue next_pop; + + // We have to consider a pop instead of a + // pop2 now. + popInstr = new Instruction(opc_pop); + isPop2 = false; + instr = (Instruction) iter.previous(); + continue; + } + + if (isPop2 + && count > 1 && count <= 4 + && opcode == (opc_dup2 + count-2)) { + iter.remove(); + continue next_pop; + } + /* Otherwise popping is not possible */ + instr = null; + break; + } + count += poppush[0] - poppush[1]; + instr = (Instruction) iter.previous(); + } + + if (instr == null) { + // We insert the pop at the previous position + while (iter.next() != popPrevious) + {} + if (!isPop2 && popPrevious.getOpcode() == opc_pop) { + // merge pop with popPrevious + iter.set(new Instruction(opc_pop2)); + } else + iter.add(popInstr); + continue; + } + int opcode = instr.getOpcode(); + switch (opcode) { + case opc_ldc2_w: + case opc_lload: case opc_dload: + if (!isPop2) + throw new AssertError("pop on long"); + iter.remove(); + continue; + case opc_ldc: + case opc_iload: case opc_fload: case opc_aload: + case opc_dup: + case opc_new: + if (isPop2) + iter.set(new Instruction(opc_pop)); + else + iter.remove(); + continue; + case opc_iaload: case opc_faload: case opc_aaload: + case opc_baload: case opc_caload: case opc_saload: + case opc_iadd: case opc_fadd: + case opc_isub: case opc_fsub: + case opc_imul: case opc_fmul: + case opc_idiv: case opc_fdiv: + case opc_irem: case opc_frem: + case opc_iand: case opc_ior : case opc_ixor: + case opc_ishl: case opc_ishr: case opc_iushr: + case opc_fcmpl: case opc_fcmpg: + /* We have to pop one entry more. */ + iter.next(); + iter.add(popInstr); + iter.previous(); + iter.previous(); + iter.set(new Instruction(opc_pop)); + continue; + + case opc_dup_x1: + iter.set(new Instruction(opc_swap)); + iter.next(); + if (isPop2) + iter.add(new Instruction(opc_pop)); + continue; + + case opc_dup2: + if (isPop2) { + iter.remove(); + continue; + } + break; + case opc_swap: + if (isPop2) { + iter.set(popInstr); + continue; + } + break; + + case opc_lneg: case opc_dneg: + case opc_l2d: case opc_d2l: + case opc_laload: case opc_daload: + if (!isPop2) + throw new AssertError("pop on long"); + /* fall through */ + case opc_ineg: case opc_fneg: + case opc_i2f: case opc_f2i: + case opc_i2b: case opc_i2c: case opc_i2s: + case opc_newarray: case opc_anewarray: + case opc_arraylength: + case opc_instanceof: + iter.set(popInstr); + continue; + + case opc_l2i: case opc_l2f: + case opc_d2i: case opc_d2f: + if (isPop2) { + iter.next(); + iter.add(new Instruction(opc_pop)); + iter.previous(); + iter.previous(); + } + iter.set(new Instruction(opc_pop2)); + continue; + + case opc_ladd: case opc_dadd: + case opc_lsub: case opc_dsub: + case opc_lmul: case opc_dmul: + case opc_ldiv: case opc_ddiv: + case opc_lrem: case opc_drem: + case opc_land: case opc_lor : case opc_lxor: + if (!isPop2) + throw new AssertError("pop on long"); + iter.next(); + iter.add(popInstr); + iter.previous(); + iter.previous(); + iter.set(new Instruction(opc_pop2)); + continue; + case opc_lshl: case opc_lshr: case opc_lushr: + if (!isPop2) + throw new AssertError("pop on long"); + iter.next(); + iter.add(popInstr); + iter.previous(); + iter.previous(); + iter.set(new Instruction(opc_pop)); + continue; + + case opc_i2l: case opc_i2d: + case opc_f2l: case opc_f2d: + if (!isPop2) + throw new AssertError("pop on long"); + iter.set(new Instruction(opc_pop)); + continue; + + case opc_lcmp: + case opc_dcmpl: case opc_dcmpg: + iter.next(); + iter.add(new Instruction(opc_pop2)); + if (isPop2) { + iter.add(new Instruction(opc_pop)); + iter.previous(); + } + iter.previous(); + iter.previous(); + iter.set(new Instruction(opc_pop2)); + continue; + + case opc_getstatic: + case opc_getfield: { + Reference ref = instr.getReference(); + int size = TypeSignature.getTypeSize(ref.getType()); + if (size == 2 && !isPop2) + throw new AssertError("pop on long"); + if (opcode == opc_getfield) + size--; + switch (size) { + case 0: + iter.set(popInstr); + break; + case 1: + if (isPop2) { + iter.set(new Instruction(opc_pop)); + break; + } + /* fall through */ + case 2: + iter.remove(); + } + continue; + } + + case opc_multianewarray: { + int dims = instr.getDimensions(); + if (--dims > 0) { + iter.next(); + while (dims-- > 0) { + iter.add(new Instruction(opc_pop)); + iter.previous(); + } + iter.previous(); + } + iter.set(popInstr); + continue; + } + + case opc_invokevirtual: + case opc_invokespecial: + case opc_invokestatic: + case opc_invokeinterface: + if (TypeSignature.getReturnSize + (instr.getReference().getType()) != 1) + break; + /* fall through */ + case opc_checkcast: + if (isPop2) { + /* This is/may be a double pop on a single value + * split it and continue with second half + */ + iter.next(); + iter.add(new Instruction(opc_pop)); + iter.add(new Instruction(opc_pop)); + iter.previous(); + continue; + } + } + // append the pop behind the unresolvable opcode. + iter.next(); + iter.add(popInstr); + continue; + } + } + } +} diff --git a/jode/jode/obfuscator/ScriptParser.java.in b/jode/jode/obfuscator/ScriptParser.java.in index 76a5988..e0f0ecf 100644 --- a/jode/jode/obfuscator/ScriptParser.java.in +++ b/jode/jode/obfuscator/ScriptParser.java.in @@ -251,7 +251,9 @@ public class ScriptParser { } catch (RuntimeException ex) { throw new ParseException(linenr, optionHandler.getClass().getName() - +": Illegal value: "+ex.getMessage()); + +": Illegal value: " + +ex.getClass().getName() + +": "+ex.getMessage()); } } } diff --git a/jode/jode/obfuscator/SimpleAnalyzer.java b/jode/jode/obfuscator/SimpleAnalyzer.java.in similarity index 84% rename from jode/jode/obfuscator/SimpleAnalyzer.java rename to jode/jode/obfuscator/SimpleAnalyzer.java.in index 7ee1077..e1dbffb 100644 --- a/jode/jode/obfuscator/SimpleAnalyzer.java +++ b/jode/jode/obfuscator/SimpleAnalyzer.java.in @@ -27,6 +27,9 @@ import jode.bytecode.Reference; import jode.GlobalOptions; import jode.type.Type; +import @COLLECTIONS@.Iterator; +import @COLLECTIONS@.ListIterator; + public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { public Identifier canonizeReference(Instruction instr) { @@ -87,8 +90,9 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { * @return an enumeration of the references. */ public void analyzeCode(MethodIdentifier m, BytecodeInfo bytecode) { - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.getNextByAddr()) { + for (Iterator iter = bytecode.getInstructions().iterator(); + iter.hasNext(); ) { + Instruction instr = (Instruction) iter.next(); switch (instr.getOpcode()) { case opc_checkcast: case opc_instanceof: @@ -98,8 +102,9 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { while (i < clName.length() && clName.charAt(i) == '[') i++; if (i < clName.length() && clName.charAt(i) == 'L') { - clName = clName.substring(i+1, clName.length()-1); - Main.getClassBundle().reachableIdentifier(clName, false); + clName = clName.substring(i+1, clName.length()-1) + .replace('/','.'); + Main.getClassBundle().reachableClass(clName); } break; } @@ -123,8 +128,7 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { } else if (instr.getOpcode() == opc_invokevirtual || instr.getOpcode() == opc_invokeinterface) { ((ClassIdentifier) ident.getParent()) - .reachableIdentifier(ident.getName(), - ident.getType(), true); + .reachableReference(instr.getReference(), true); } else { ident.setReachable(); } @@ -138,13 +142,14 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { for (int i=0; i< handlers.length; i++) { if (handlers[i].type != null) Main.getClassBundle() - .reachableIdentifier(handlers[i].type, false); + .reachableClass(handlers[i].type); } } public void transformCode(BytecodeInfo bytecode) { - for (Instruction instr = bytecode.getFirstInstr(); - instr != null; instr = instr.getNextByAddr()) { + for (ListIterator iter = bytecode.getInstructions().listIterator(); + iter.hasNext(); ) { + Instruction instr = (Instruction) iter.next(); if (instr.getOpcode() == opc_putstatic || instr.getOpcode() == opc_putfield) { Reference ref = instr.getReference(); @@ -158,13 +163,18 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { (instr.getOpcode() == Instruction.opc_putstatic) ? 0 : 1; stacksize += Type.tType(ref.getType()).stackSize(); - if (stacksize == 3) { - /* Add a pop instruction after this opcode. */ - instr.appendInstruction(Instruction.opc_pop); - stacksize--; + switch (stacksize) { + case 1: + iter.set(new Instruction(Instruction.opc_pop)); + break; + case 2: + iter.set(new Instruction(Instruction.opc_pop2)); + break; + case 3: + iter.set(new Instruction(Instruction.opc_pop2)); + iter.add(new Instruction(Instruction.opc_pop)); + break; } - instr.replaceInstruction(Instruction.opc_pop - 1 - + stacksize); } } } diff --git a/jode/jode/obfuscator/UniqueRenamer.java.in b/jode/jode/obfuscator/UniqueRenamer.java.in index c97719d..0ed1a24 100644 --- a/jode/jode/obfuscator/UniqueRenamer.java.in +++ b/jode/jode/obfuscator/UniqueRenamer.java.in @@ -1,6 +1,7 @@ package jode.obfuscator; import @COLLECTIONS@.Iterator; +import @COLLECTIONEXTRA@.UnsupportedOperationException; public class UniqueRenamer implements Renamer { static int serialnr = 0;