From f8384e992840e3f30f5385119139a0e767965c84 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 24 Oct 1999 23:54:51 +0000 Subject: [PATCH] move modules into separate package serializable reworked (may be buggy still) git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1173 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/obfuscator/ClassBundle.java.in | 3 + jode/jode/obfuscator/ClassIdentifier.java.in | 72 +- jode/jode/obfuscator/ConstantAnalyzer.java.in | 1706 ----------------- jode/jode/obfuscator/FieldIdentifier.java.in | 9 + jode/jode/obfuscator/Identifier.java.in | 6 +- jode/jode/obfuscator/LocalOptimizer.java.in | 940 --------- .../LocalizeFieldTransformer.java.in | 34 - jode/jode/obfuscator/Makefile.am | 15 +- jode/jode/obfuscator/MethodIdentifier.java.in | 4 + jode/jode/obfuscator/ModifierMatcher.java | 269 --- .../obfuscator/MultiIdentifierMatcher.java.in | 109 -- jode/jode/obfuscator/NameSwapper.java.in | 98 - .../jode/obfuscator/PackageIdentifier.java.in | 7 +- .../jode/obfuscator/RemovePopAnalyzer.java.in | 307 --- jode/jode/obfuscator/ScriptParser.java.in | 3 +- jode/jode/obfuscator/SimpleAnalyzer.java.in | 182 -- jode/jode/obfuscator/StrongRenamer.java.in | 141 -- jode/jode/obfuscator/UniqueRenamer.java.in | 41 - jode/jode/obfuscator/WildCard.java.in | 108 -- 19 files changed, 56 insertions(+), 3998 deletions(-) delete mode 100644 jode/jode/obfuscator/ConstantAnalyzer.java.in delete mode 100644 jode/jode/obfuscator/LocalOptimizer.java.in delete mode 100644 jode/jode/obfuscator/LocalizeFieldTransformer.java.in delete mode 100644 jode/jode/obfuscator/ModifierMatcher.java delete mode 100644 jode/jode/obfuscator/MultiIdentifierMatcher.java.in delete mode 100644 jode/jode/obfuscator/NameSwapper.java.in delete mode 100644 jode/jode/obfuscator/RemovePopAnalyzer.java.in delete mode 100644 jode/jode/obfuscator/SimpleAnalyzer.java.in delete mode 100644 jode/jode/obfuscator/StrongRenamer.java.in delete mode 100644 jode/jode/obfuscator/UniqueRenamer.java.in delete mode 100644 jode/jode/obfuscator/WildCard.java.in diff --git a/jode/jode/obfuscator/ClassBundle.java.in b/jode/jode/obfuscator/ClassBundle.java.in index e4c048b..0e0f0d7 100644 --- a/jode/jode/obfuscator/ClassBundle.java.in +++ b/jode/jode/obfuscator/ClassBundle.java.in @@ -22,6 +22,9 @@ import jode.GlobalOptions; import jode.bytecode.SearchPath; import jode.bytecode.ClassInfo; import jode.bytecode.Reference; +import jode.obfuscator.modules.WildCard; +import jode.obfuscator.modules.MultiIdentifierMatcher; +import jode.obfuscator.modules.SimpleAnalyzer; import java.io.*; import java.util.zip.ZipOutputStream; diff --git a/jode/jode/obfuscator/ClassIdentifier.java.in b/jode/jode/obfuscator/ClassIdentifier.java.in index 5943bcc..9894f43 100644 --- a/jode/jode/obfuscator/ClassIdentifier.java.in +++ b/jode/jode/obfuscator/ClassIdentifier.java.in @@ -20,6 +20,7 @@ package jode.obfuscator; import jode.GlobalOptions; import jode.bytecode.*; +import jode.obfuscator.modules.ModifierMatcher; import @COLLECTIONS@.Comparator; import @COLLECTIONS@.Collection; import @COLLECTIONS@.Collections; @@ -251,48 +252,26 @@ public class ClassIdentifier extends Identifier { } } - /** - * Preserve all fields, that are necessary, to serialize - * a compatible class. - */ - public void preserveSerializable() { - Identifier method - = findMethod("writeObject", "(Ljava.io.ObjectOutputStream)V"); - if (method != null) - method.setPreserved(); - method = findMethod("readObject", "(Ljava.io.ObjectInputStream)V"); - if (method != null) - method.setPreserved(); - if ((Main.options & Main.OPTION_PRESERVESERIAL) != 0) { - setPreserved(); - Identifier UIDident = findField("serialVersionUID", "J"); - if (UIDident == null) { - /* add a field serializableVersionUID if not existent */ - long serialVersion = calcSerialVersionUID(); - FieldInfo UIDField = new FieldInfo - (info, "serialVersionUID", "J", - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL); - UIDField.setConstant(new Long(serialVersion)); - UIDident = new FieldIdentifier(this, UIDField); - fieldIdents.add(UIDident); - } - UIDident.setReachable(); - UIDident.setPreserved(); - for (Iterator i=getFieldIdents().iterator(); i.hasNext(); ) { - FieldIdentifier ident = (FieldIdentifier) i.next(); - if ((ident.info.getModifiers() - & (Modifier.TRANSIENT | Modifier.STATIC)) == 0) { - ident.setPreserved(); - ident.setNotConstant(); - } - /* XXX - only preserve them if writeObject not existent - * or if writeObject calls defaultWriteObject, and similar - * for readObject - */ - } - } + public void addSUID() { + /* add a field serializableVersionUID if not existent */ + long serialVersion = calcSerialVersionUID(); + FieldInfo UIDField = new FieldInfo + (info, "serialVersionUID", "J", + Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL); + UIDField.setConstant(new Long(serialVersion)); + FieldIdentifier UIDident = new FieldIdentifier(this, UIDField); + fieldIdents.add(UIDident); + UIDident.setPreserved(); } + public boolean isSerializable() { + return ClassInfo.forName("java.lang.Serializable") + .implementedBy(info); + } + public boolean hasSUID() { + return (findField("serialVersionUID", "J") != null); + } + /** * Marks the package as preserved, too. */ @@ -307,8 +286,6 @@ public class ClassIdentifier extends Identifier { public void analyzeSuperClasses(ClassInfo superclass) { while (superclass != null) { - if (superclass.getName().equals("java.io.Serializable")) - preserveSerializable(); ClassIdentifier superident = Main.getClassBundle() .getClassIdentifier(superclass.getName()); @@ -351,9 +328,6 @@ public class ClassIdentifier extends Identifier { public void initSuperClasses(ClassInfo superclass) { while (superclass != null) { - if (superclass.getName().equals("java.lang.Serializable")) - preserveSerializable(); - ClassIdentifier superident = Main.getClassBundle() .getClassIdentifier(superclass.getName()); if (superident != null) { @@ -736,6 +710,10 @@ public class ClassIdentifier extends Identifier { public String getType() { return "Ljava/lang/Class;"; } + + public int getModifiers() { + return info.getModifiers(); + } public List getFieldIdents() { return fieldIdents; @@ -796,7 +774,7 @@ public class ClassIdentifier extends Identifier { } public boolean containsFieldAliasDirectly(String fieldName, String typeSig, - ModifierMatcher matcher) { + IdentifierMatcher matcher) { for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) { Identifier ident = (Identifier) i.next(); if (((Main.stripping & Main.STRIP_UNREACH) == 0 @@ -812,7 +790,7 @@ public class ClassIdentifier extends Identifier { public boolean containsMethodAliasDirectly(String methodName, String paramType, - ModifierMatcher matcher) { + IdentifierMatcher matcher) { for (Iterator i = methodIdents.iterator(); i.hasNext(); ) { Identifier ident = (Identifier) i.next(); if (((Main.stripping & Main.STRIP_UNREACH) == 0 diff --git a/jode/jode/obfuscator/ConstantAnalyzer.java.in b/jode/jode/obfuscator/ConstantAnalyzer.java.in deleted file mode 100644 index 5dd5ad4..0000000 --- a/jode/jode/obfuscator/ConstantAnalyzer.java.in +++ /dev/null @@ -1,1706 +0,0 @@ -/* ConstantAnalyzer 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.AssertError; -import jode.GlobalOptions; -import jode.bytecode.*; -import jode.jvm.InterpreterException; - -import java.lang.reflect.Array; -import java.lang.reflect.Modifier; -import java.lang.reflect.InvocationTargetException; -import java.util.BitSet; - -import @COLLECTIONS@.Arrays; -import @COLLECTIONS@.Collection; -import @COLLECTIONS@.HashSet; -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 - * is constant. This may imply that some code is dead code. - * - * @author Jochen Hoenicke - */ -public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { - - BytecodeInfo bytecode; - - private static ConstantRuntimeEnvironment runtime - = new ConstantRuntimeEnvironment(); - - private final static int CMP_EQ = 0; - private final static int CMP_NE = 1; - private final static int CMP_LT = 2; - private final static int CMP_GE = 3; - private final static int CMP_GT = 4; - private final static int CMP_LE = 5; - private final static int CMP_GREATER_MASK - = (1 << CMP_GT)|(1 << CMP_GE)|(1 << CMP_NE); - private final static int CMP_LESS_MASK - = (1 << CMP_LT)|(1 << CMP_LE)|(1 << CMP_NE); - private final static int CMP_EQUAL_MASK - = (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ); - - 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 final static class JSRTargetInfo implements Cloneable { - Instruction jsrTarget; - BitSet usedLocals; - - /** - * 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; - usedLocals = new BitSet(); - } - - public JSRTargetInfo copy() { - 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) { - 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 (dependent instanceof StackLocalInfo) - sb.append("->").append(((StackLocalInfo) dependent).instr); - return sb.append(usedLocals) - .append('_').append(hashCode()).toString(); - } - } - - private static class ConstValue implements ConstantListener { - public final static Object VOLATILE = new Object(); - /** - * The constant value, VOLATILE if value is not constant. - * This may also be an instance of JSRTargetInfo - */ - Object value; - /** - * The number of slots this value takes on the stack. - */ - int stackSize; - /** - * The constant listeners, that want to be informed if this is - * no longer constant. - */ - Set listeners; - - public ConstValue(Object constant) { - value = constant; - stackSize = (constant instanceof Double - || constant instanceof Long) ? 2 : 1; - listeners = new HashSet(); - } - - public ConstValue(ConstValue constant) { - value = constant.value; - stackSize = constant.stackSize; - listeners = new HashSet(); - constant.addConstantListener(this); - } - - public ConstValue(int stackSize) { - this.value = VOLATILE; - this.stackSize = stackSize; - } - - public ConstValue copy() { - return (value == VOLATILE) ? this - : new ConstValue(this); - } - - public void addConstantListener(ConstantListener l) { - listeners.add(l); - } - - public void removeConstantListener(ConstantListener l) { - listeners.remove(l); - } - - public void fireChanged() { - value = VOLATILE; - for (Iterator i = listeners.iterator(); i.hasNext(); ) - ((ConstantListener) i.next()).constantChanged(); - listeners = null; - } - - public void constantChanged() { - if (value != VOLATILE) - fireChanged(); - } - - /** - * Merge the other value into this value. - */ - public void merge(ConstValue other) { - if (this == other) - return; - - if (value == null ? other.value == null - : value.equals(other.value)) { - if (value != VOLATILE) { -// other.addConstantListener(this); - this.addConstantListener(other); - } - return; - } - - if (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) -// other.fireChanged(); - } - - public String toString() { - return value == VOLATILE ? "vol("+stackSize+")" : ""+value; - } - } - - private static class TodoQueue { - StackLocalInfo first; - } - - private static class StackLocalInfo implements ConstantListener { - ConstValue[] stack; - ConstValue[] locals; - Instruction instr; - ConstantInfo constInfo; - StackLocalInfo retInfo; - - StackLocalInfo nextOnQueue; - - /** - * The queue that should be notified, if the constant values of - * this instruction changes. We put ourself on this queue in that - * case. - */ - TodoQueue notifyQueue; - - public ConstValue copy(ConstValue value) { - return (value == null) ? null : value.copy(); - } - - private StackLocalInfo(ConstValue[] stack, - ConstValue[] locals, - TodoQueue notifyQueue) { - this.stack = stack; - this.locals = locals; - this.notifyQueue = notifyQueue; - } - - public StackLocalInfo(int numLocals, - boolean isStatic, String methodTypeSig, - TodoQueue notifyQueue) { - - String[] paramTypes - = TypeSignature.getParameterTypes(methodTypeSig); - locals = new ConstValue[numLocals]; - stack = new ConstValue[0]; - this.notifyQueue = notifyQueue; - int slot = 0; - if (!isStatic) - locals[slot++] = new ConstValue(1); - for (int i=0; i< paramTypes.length; i++) { - int stackSize = TypeSignature.getTypeSize(paramTypes[i]); - locals[slot] = unknownValue[stackSize-1]; - slot += stackSize; - } - } - - public final void enqueue() { - if (nextOnQueue == null) { - this.nextOnQueue = notifyQueue.first; - notifyQueue.first = this; - } - } - - public void constantChanged() { - enqueue(); - } - - public StackLocalInfo poppush(int pops, ConstValue push) { - ConstValue[] newStack - = new ConstValue[stack.length - pops + push.stackSize]; - ConstValue[] newLocals = (ConstValue[]) locals.clone(); - System.arraycopy(stack, 0, newStack, 0, stack.length-pops); - newStack[stack.length-pops] = push.copy(); - return new StackLocalInfo(newStack, newLocals, notifyQueue); - } - - public StackLocalInfo pop(int pops) { - ConstValue[] newStack - = new ConstValue[stack.length - pops]; - ConstValue[] newLocals = (ConstValue[]) locals.clone(); - System.arraycopy(stack, 0, newStack, 0, stack.length-pops); - return new StackLocalInfo(newStack, newLocals, notifyQueue); - } - - public StackLocalInfo dup(int count, int depth) { - ConstValue[] newStack - = new ConstValue[stack.length + count]; - ConstValue[] newLocals = (ConstValue[]) locals.clone(); - if (depth == 0) - System.arraycopy(stack, 0, newStack, 0, stack.length); - else { - int pos = stack.length - count - depth; - System.arraycopy(stack, 0, newStack, 0, pos); - for (int i=0; i < count; i++) - newStack[pos++] = copy(stack[stack.length-count + i]); - for (int i=0; i < depth; i++) - newStack[pos++] = copy(stack[stack.length-count-depth + i]); - } - for (int i=0; i < count; i++) - newStack[stack.length+i] = copy(stack[stack.length-count + i]); - return new StackLocalInfo(newStack, newLocals, notifyQueue); - } - - public StackLocalInfo swap() { - ConstValue[] newStack - = new ConstValue[stack.length]; - ConstValue[] newLocals = (ConstValue[]) locals.clone(); - System.arraycopy(stack, 0, newStack, 0, stack.length - 2); - newStack[stack.length-2] = stack[stack.length-1].copy(); - newStack[stack.length-1] = stack[stack.length-2].copy(); - return new StackLocalInfo(newStack, newLocals, notifyQueue); - } - - public StackLocalInfo copy() { - ConstValue[] newStack = (ConstValue[]) stack.clone(); - ConstValue[] newLocals = (ConstValue[]) locals.clone(); - return new StackLocalInfo(newStack, newLocals, notifyQueue); - } - - public ConstValue getLocal(int slot) { - return locals[slot]; - } - - public ConstValue getStack(int depth) { - return stack[stack.length - depth]; - } - - public StackLocalInfo setLocal(int slot, ConstValue value) { - locals[slot] = value; - if (value != null && value.stackSize == 2) - locals[slot+1] = null; - for (int i=0; i< locals.length; i++) { - if (locals[i] != null - && locals[i].value instanceof JSRTargetInfo) { - 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 = jsrInfo; - for (int slot = 0; slot < locals.length; slot++) { - if (jsrTargetInfo.uses(slot)) - 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; - 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) { - for (int i=0; i < locals.length; i++) { - if (locals[i] != null) { - if (other.locals[i] == null) { - locals[i] = null; - enqueue(); - } else { - locals[i].merge(other.locals[i]); - } - } - } - if (stack.length != other.stack.length) - throw new jode.AssertError("stack length differs"); - for (int i=0; i < stack.length; i++) { - if ((other.stack[i] == null) != (stack[i] == null)) - throw new jode.AssertError("stack types differ"); - else if (stack[i] != null) - stack[i].merge(other.stack[i]); - } - } - - public String toString() { - return "Locals: "+Arrays.asList(locals) - +"Stack: "+Arrays.asList(stack)+ "Instr: "+instr; - } - } - - private static class ConstantInfo implements ConstantListener { - ConstantInfo() { - this(0, null); - } - - ConstantInfo(int flags) { - this(flags, null); - } - - ConstantInfo(int flags, Object constant) { - this.flags = flags; - this.constant = constant; - } - - int flags; - /** - * The constant, may be an Instruction for CONSTANTFLOW. - */ - Object constant; - - public void constantChanged() { - constant = null; - flags &= ~(CONSTANT | CONSTANTFLOW); - } - } - - private static ConstValue[] unknownValue = { - new ConstValue(1), new ConstValue(2) - }; - - private static ConstantInfo unknownConstInfo = new ConstantInfo(); - - public ConstantAnalyzer() { - } - - public void mergeInfo(Instruction instr, - StackLocalInfo info) { - if (instr.getTmpInfo() == null) { - instr.setTmpInfo(info); - info.instr = instr; - info.enqueue(); - } else - ((StackLocalInfo)instr.getTmpInfo()).merge(info); - } - - public Identifier canonizeReference(Instruction instr) { - Reference ref = instr.getReference(); - Identifier ident = Main.getClassBundle().getIdentifier(ref); - String clName = ref.getClazz(); - String realClazzName; - if (ident != null) { - ClassIdentifier clazz = (ClassIdentifier)ident.getParent(); - realClazzName = "L" + (clazz.getFullName() - .replace('.', '/')) + ";"; - } else { - /* We have to look at the ClassInfo's instead, to - * point to the right method. - */ - ClassInfo clazz; - if (clName.charAt(0) == '[') { - /* Arrays don't define new methods (well clone(), - * but that can be ignored). - */ - clazz = ClassInfo.javaLangObject; - } else { - clazz = ClassInfo.forName - (clName.substring(1, clName.length()-1) - .replace('/','.')); - } - if (instr.getOpcode() >= opc_invokevirtual) { - while (clazz != null - && clazz.findMethod(ref.getName(), - ref.getType()) == null) - clazz = clazz.getSuperclass(); - } else { - while (clazz != null - && clazz.findField(ref.getName(), - ref.getType()) == null) - clazz = clazz.getSuperclass(); - } - - if (clazz == null) { - GlobalOptions.err.println("WARNING: Can't find reference: " - +ref); - realClazzName = clName; - } else - realClazzName = "L" + clazz.getName().replace('.', '/') + ";"; - } - if (!realClazzName.equals(ref.getClazz())) { - ref = Reference.getReference(realClazzName, - ref.getName(), ref.getType()); - instr.setReference(ref); - } - return ident; - } - - public void handleReference(Reference ref, boolean isVirtual) { - Main.getClassBundle().reachableReference(ref, isVirtual); - } - - public void handleClass(String clName) { - int i = 0; - 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().reachableClass(clName); - } - } - - public void handleOpcode(StackLocalInfo info, Identifier fieldListener) { - Instruction instr = info.instr; - info.constInfo = unknownConstInfo; - - int opcode = instr.getOpcode(); - Handler[] handlers = bytecode.getExceptionHandlers(); - for (int i=0; i< handlers.length; i++) { - if (handlers[i].start.getAddr() <= instr.getAddr() - && handlers[i].end.getAddr() >= instr.getAddr()) - mergeInfo(handlers[i].catcher, - info.poppush(info.stack.length, unknownValue[0])); - } - ConstValue result; - switch (opcode) { - case opc_nop: - mergeInfo(instr.getNextByAddr(), info.pop(0)); - break; - - case opc_ldc: - case opc_ldc2_w: - result = new ConstValue(instr.getConstant()); - mergeInfo(instr.getNextByAddr(), info.poppush(0, result)); - break; - - case opc_iload: case opc_lload: - case opc_fload: case opc_dload: case opc_aload: - result = info.getLocal(instr.getLocalSlot()); - if (result == null) { - dumpStackLocalInfo(); - System.err.println(info); - System.err.println(instr); - } - if (result.value != ConstValue.VOLATILE) { - info.constInfo = new ConstantInfo(CONSTANT, result.value); - result.addConstantListener(info.constInfo); - } - mergeInfo(instr.getNextByAddr(), - info.poppush(0, result) - .setLocal(instr.getLocalSlot(), result.copy())); - break; - case opc_iaload: case opc_laload: - case opc_faload: case opc_daload: case opc_aaload: - case opc_baload: case opc_caload: case opc_saload: { -// ConstValue array = info.getStack(2); -// ConstValue index = info.getStack(1); -// ConstValue newValue = null; -// if (index.value != index.ConstValue.VOLATILE -// && array.value != array.ConstValue.VOLATILE -// && array.value != null) { -// int indexVal = ((Integer) index.value).intValue(); -// Object content; -// switch(opcode) { -// case opc_baload: -// content = new Integer -// (array.value instanceof byte[] -// ? ((byte[])array.value)[indexVal] -// : ((boolean[])array.value)[indexVal] ? 1 : 0); -// case opc_caload: -// content = new Integer(((char[])array.value)[indexVal]); -// break; -// case opc_saload: -// content = new Integer(((short[])array.value)[indexVal]); -// break; -// case opc_iaload: -// case opc_laload: -// case opc_faload: -// case opc_daload: -// case opc_aaload: -// content = Array.get(array.value, indexVal); -// break; -// default: -// throw new jode.AssertError("Can't happen."); -// } -// result = new ConstValue(content); -// array.addConstantListener(result); -// index.addConstantListener(result); -// } else { - result = unknownValue[(opcode == opc_laload - || opcode == opc_daload) ? 1 : 0]; -// } - mergeInfo(instr.getNextByAddr(), info.poppush(2, result)); - 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(), result)); - break; - } - case opc_lstore: case opc_dstore: { - mergeInfo(instr.getNextByAddr(), - info.pop(2).setLocal(instr.getLocalSlot(), info.getStack(2))); - break; - } - case opc_iastore: case opc_lastore: - case opc_fastore: case opc_dastore: case opc_aastore: - case opc_bastore: case opc_castore: case opc_sastore: { - int size = (opcode == opc_lastore - || opcode == opc_dastore) ? 2 : 1; - mergeInfo(instr.getNextByAddr(), info.pop(2+size)); - break; - } - 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: - case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: - mergeInfo(instr.getNextByAddr(), - info.dup((opcode - (opc_dup - 3)) / 3, - (opcode - (opc_dup - 3)) % 3)); - break; - case opc_swap: - mergeInfo(instr.getNextByAddr(), info.swap()); - break; - - case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: - case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub: - case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: - case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: - case opc_irem: case opc_lrem: case opc_frem: case opc_drem: - case opc_iand: case opc_land: - case opc_ior : case opc_lor : - case opc_ixor: case opc_lxor: { - int size = 1 + (opcode - opc_iadd & 1); - ConstValue value1 = info.getStack(2*size); - ConstValue value2 = info.getStack(1*size); - boolean known = value1.value != ConstValue.VOLATILE - && value2.value != ConstValue.VOLATILE; - if (known) { - if ((opcode == opc_idiv - && ((Integer)value2.value).intValue() == 0) - || (opcode == opc_ldiv - && ((Long)value2.value).longValue() == 0)) - known = false; - } - if (known) { - Object newValue; - switch (opcode) { - case opc_iadd: - newValue = new Integer - (((Integer)value1.value).intValue() - + ((Integer)value2.value).intValue()); - break; - case opc_isub: - newValue = new Integer - (((Integer)value1.value).intValue() - - ((Integer)value2.value).intValue()); - break; - case opc_imul: - newValue = new Integer - (((Integer)value1.value).intValue() - * ((Integer)value2.value).intValue()); - break; - case opc_idiv: - newValue = new Integer - (((Integer)value1.value).intValue() - / ((Integer)value2.value).intValue()); - break; - case opc_irem: - newValue = new Integer - (((Integer)value1.value).intValue() - % ((Integer)value2.value).intValue()); - break; - case opc_iand: - newValue = new Integer - (((Integer)value1.value).intValue() - & ((Integer)value2.value).intValue()); - break; - case opc_ior: - newValue = new Integer - (((Integer)value1.value).intValue() - | ((Integer)value2.value).intValue()); - break; - case opc_ixor: - newValue = new Integer - (((Integer)value1.value).intValue() - ^ ((Integer)value2.value).intValue()); - break; - - case opc_ladd: - newValue = new Long - (((Long)value1.value).longValue() - + ((Long)value2.value).longValue()); - break; - case opc_lsub: - newValue = new Long - (((Long)value1.value).longValue() - - ((Long)value2.value).longValue()); - break; - case opc_lmul: - newValue = new Long - (((Long)value1.value).longValue() - * ((Long)value2.value).longValue()); - break; - case opc_ldiv: - newValue = new Long - (((Long)value1.value).longValue() - / ((Long)value2.value).longValue()); - break; - case opc_lrem: - newValue = new Long - (((Long)value1.value).longValue() - % ((Long)value2.value).longValue()); - break; - case opc_land: - newValue = new Long - (((Long)value1.value).longValue() - & ((Long)value2.value).longValue()); - break; - case opc_lor: - newValue = new Long - (((Long)value1.value).longValue() - | ((Long)value2.value).longValue()); - break; - case opc_lxor: - newValue = new Long - (((Long)value1.value).longValue() - ^ ((Long)value2.value).longValue()); - break; - - case opc_fadd: - newValue = new Float - (((Float)value1.value).floatValue() - + ((Float)value2.value).floatValue()); - break; - case opc_fsub: - newValue = new Float - (((Float)value1.value).floatValue() - - ((Float)value2.value).floatValue()); - break; - case opc_fmul: - newValue = new Float - (((Float)value1.value).floatValue() - * ((Float)value2.value).floatValue()); - break; - case opc_fdiv: - newValue = new Float - (((Float)value1.value).floatValue() - / ((Float)value2.value).floatValue()); - break; - case opc_frem: - newValue = new Float - (((Float)value1.value).floatValue() - % ((Float)value2.value).floatValue()); - break; - - case opc_dadd: - newValue = new Double - (((Double)value1.value).doubleValue() - + ((Double)value2.value).doubleValue()); - break; - case opc_dsub: - newValue = new Double - (((Double)value1.value).doubleValue() - - ((Double)value2.value).doubleValue()); - break; - case opc_dmul: - newValue = new Double - (((Double)value1.value).doubleValue() - * ((Double)value2.value).doubleValue()); - break; - case opc_ddiv: - newValue = new Double - (((Double)value1.value).doubleValue() - / ((Double)value2.value).doubleValue()); - break; - case opc_drem: - newValue = new Double - (((Double)value1.value).doubleValue() - % ((Double)value2.value).doubleValue()); - break; - default: - throw new jode.AssertError("Can't happen."); - } - info.constInfo = new ConstantInfo(CONSTANT, newValue); - result = new ConstValue(newValue); - result.addConstantListener(info.constInfo); - value1.addConstantListener(result); - value2.addConstantListener(result); - } else - result = unknownValue[size-1]; - mergeInfo(instr.getNextByAddr(), info.poppush(2*size, result)); - break; - } - case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: { - int size = 1 + (opcode - opc_ineg & 1); - ConstValue value = info.getStack(size); - if (value.value != ConstValue.VOLATILE) { - Object newValue; - switch (opcode) { - case opc_ineg: - newValue = new Integer - (-((Integer)value.value).intValue()); - break; - case opc_lneg: - newValue = new Long - (- ((Long)value.value).longValue()); - break; - case opc_fneg: - newValue = new Float - (- ((Float)value.value).floatValue()); - break; - case opc_dneg: - newValue = new Double - (- ((Double)value.value).doubleValue()); - break; - default: - throw new jode.AssertError("Can't happen."); - } - info.constInfo = new ConstantInfo(CONSTANT, newValue); - result = new ConstValue(newValue); - result.addConstantListener(info.constInfo); - value.addConstantListener(result); - } else - result = unknownValue[size-1]; - mergeInfo(instr.getNextByAddr(), info.poppush(size, result)); - break; - } - case opc_ishl: case opc_lshl: - case opc_ishr: case opc_lshr: - case opc_iushr: case opc_lushr: { - int size = 1 + (opcode - opc_iadd & 1); - ConstValue value1 = info.getStack(size+1); - ConstValue value2 = info.getStack(1); - if (value1.value != ConstValue.VOLATILE - && value2.value != ConstValue.VOLATILE) { - Object newValue; - switch (opcode) { - case opc_ishl: - newValue = new Integer - (((Integer)value1.value).intValue() - << ((Integer)value2.value).intValue()); - break; - case opc_ishr: - newValue = new Integer - (((Integer)value1.value).intValue() - >> ((Integer)value2.value).intValue()); - break; - case opc_iushr: - newValue = new Integer - (((Integer)value1.value).intValue() - >>> ((Integer)value2.value).intValue()); - break; - - case opc_lshl: - newValue = new Long - (((Long)value1.value).longValue() - << ((Integer)value2.value).intValue()); - break; - case opc_lshr: - newValue = new Long - (((Long)value1.value).longValue() - >> ((Integer)value2.value).intValue()); - break; - case opc_lushr: - newValue = new Long - (((Long)value1.value).longValue() - >>> ((Integer)value2.value).intValue()); - break; - default: - throw new jode.AssertError("Can't happen."); - } - info.constInfo = new ConstantInfo(CONSTANT, newValue); - result = new ConstValue(newValue); - result.addConstantListener(info.constInfo); - value1.addConstantListener(result); - value2.addConstantListener(result); - } else - result = unknownValue[size-1]; - mergeInfo(instr.getNextByAddr(), info.poppush(size+1, result)); - break; - } - case opc_iinc: { - ConstValue local = info.getLocal(instr.getLocalSlot()); - if (local.value != ConstValue.VOLATILE) { - result = new ConstValue - (new Integer(((Integer)local.value).intValue() - + instr.getIncrement())); - local.addConstantListener(result); - } else - result = unknownValue[0]; - mergeInfo(instr.getNextByAddr(), - info.copy().setLocal(instr.getLocalSlot(), result)); - break; - } - case opc_i2l: case opc_i2f: case opc_i2d: - case opc_l2i: case opc_l2f: case opc_l2d: - case opc_f2i: case opc_f2l: case opc_f2d: - case opc_d2i: case opc_d2l: case opc_d2f: { - int insize = 1 + ((opcode - opc_i2l) / 3 & 1); - ConstValue stack = info.getStack(insize); - if (stack.value != ConstValue.VOLATILE) { - Object newVal; - switch(opcode) { - case opc_l2i: case opc_f2i: case opc_d2i: - newVal = new Integer(((Number)stack.value).intValue()); - break; - case opc_i2l: case opc_f2l: case opc_d2l: - newVal = new Long(((Number)stack.value).longValue()); - break; - case opc_i2f: case opc_l2f: case opc_d2f: - newVal = new Float(((Number)stack.value).floatValue()); - break; - case opc_i2d: case opc_l2d: case opc_f2d: - newVal = new Double(((Number)stack.value).doubleValue()); - break; - default: - throw new jode.AssertError("Can't happen."); - } - info.constInfo = new ConstantInfo(CONSTANT, newVal); - result = new ConstValue(newVal); - result.addConstantListener(info.constInfo); - stack.addConstantListener(result); - } else { - switch (opcode) { - case opc_i2l: case opc_f2l: case opc_d2l: - case opc_i2d: case opc_l2d: case opc_f2d: - result = unknownValue[1]; - break; - default: - result = unknownValue[0]; - } - } - mergeInfo(instr.getNextByAddr(), info.poppush(insize, result)); - break; - } - case opc_i2b: case opc_i2c: case opc_i2s: { - ConstValue stack = info.getStack(1); - if (stack.value != ConstValue.VOLATILE) { - int val = ((Integer)stack.value).intValue(); - switch(opcode) { - case opc_i2b: - val = (byte) val; - break; - case opc_i2c: - val = (char) val; - break; - case opc_i2s: - val = (short) val; - break; - } - 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]; - mergeInfo(instr.getNextByAddr(), - info.poppush(1, result)); - break; - } - case opc_lcmp: { - ConstValue val1 = info.getStack(4); - ConstValue val2 = info.getStack(2); - if (val1.value != ConstValue.VOLATILE - && val2.value != ConstValue.VOLATILE) { - long value1 = ((Long) val1.value).longValue(); - long value2 = ((Long) val1.value).longValue(); - 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 - result = unknownValue[0]; - mergeInfo(instr.getNextByAddr(), info.poppush(4, result)); - break; - } - case opc_fcmpl: case opc_fcmpg: { - ConstValue val1 = info.getStack(2); - ConstValue val2 = info.getStack(1); - if (val1.value != ConstValue.VOLATILE - && val2.value != ConstValue.VOLATILE) { - float value1 = ((Float) val1.value).floatValue(); - float value2 = ((Float) val1.value).floatValue(); - Integer newVal = new Integer - (value1 == value2 ? 0 - : ( opcode == opc_fcmpg - ? (value1 < value2 ? -1 : 1) - : (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 - result = unknownValue[0]; - mergeInfo(instr.getNextByAddr(), info.poppush(2, result)); - break; - } - case opc_dcmpl: case opc_dcmpg: { - ConstValue val1 = info.getStack(4); - ConstValue val2 = info.getStack(2); - if (val1.value != ConstValue.VOLATILE - && val2.value != ConstValue.VOLATILE) { - double value1 = ((Double) val1.value).doubleValue(); - double value2 = ((Double) val1.value).doubleValue(); - Integer newVal = new Integer - (value1 == value2 ? 0 - : ( opcode == opc_dcmpg - ? (value1 < value2 ? -1 : 1) - : (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 - result = unknownValue[0]; - mergeInfo(instr.getNextByAddr(), info.poppush(4, result)); - break; - } - case opc_ifeq: case opc_ifne: - case opc_iflt: case opc_ifge: - case opc_ifgt: case opc_ifle: - 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_ifnull: case opc_ifnonnull: { - int size = 1; - ConstValue stacktop = info.getStack(1); - ConstValue other = null; - boolean known = stacktop.value != ConstValue.VOLATILE; - if (opcode >= opc_if_icmpeq && opcode <= opc_if_acmpne) { - other = info.getStack(2); - size = 2; - known &= other.value != ConstValue.VOLATILE; - } - if (known) { - stacktop.addConstantListener(info); - if (other != null) - other.addConstantListener(info); - - Instruction pc = instr.getNextByAddr(); - int opc_mask; - if (opcode >= opc_if_acmpeq) { - if (opcode >= opc_ifnull) { - opc_mask = stacktop.value == null - ? CMP_EQUAL_MASK : CMP_GREATER_MASK; - opcode -= opc_ifnull; - } else { - opc_mask = stacktop.value == other.value - ? CMP_EQUAL_MASK : CMP_GREATER_MASK; - opcode -= opc_if_acmpeq; - } - } else { - int value = ((Integer) stacktop.value).intValue(); - if (opcode >= opc_if_icmpeq) { - int val1 = ((Integer) other.value).intValue(); - opc_mask = (val1 == value ? CMP_EQUAL_MASK - : val1 < value ? CMP_LESS_MASK - : CMP_GREATER_MASK); - opcode -= opc_if_icmpeq; - } else { - opc_mask = (value == 0 ? CMP_EQUAL_MASK - : value < 0 ? CMP_LESS_MASK - : CMP_GREATER_MASK); - opcode -= opc_ifeq; - } - } - - if ((opc_mask & (1<= 0; i--) { - size += TypeSignature.getTypeSize(paramTypes[i]); - Object value = (argValues[i] = info.getStack(size)).value; - if (value != ConstValue.VOLATILE) - args[i] = value; - else - constant = false; - } - - if (opcode != opc_invokestatic) { - size++; - clsValue = info.getStack(size); - cls = clsValue.value; - if (cls == ConstValue.VOLATILE || cls == null) - constant = false; - } - String retType = TypeSignature.getReturnType(ref.getType()); - if (retType.equals("V")) { - handleReference(ref, opcode == opc_invokevirtual - || opcode == opc_invokeinterface); - mergeInfo(instr.getNextByAddr(), info.pop(size)); - break; - } - if (constant && !runtime.isWhite(retType)) { - /* This is not a valid constant type */ - constant = false; - } - Object methodResult = null; - if (constant) { - try { - methodResult = runtime.invokeMethod - (ref, opcode != opc_invokespecial, cls, args); - } catch (InterpreterException ex) { - constant = false; - if (jode.GlobalOptions.verboseLevel > 3) - GlobalOptions.err.println("Can't interpret "+ref+": " - + 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()); - /* method always throws exception ? */ - } - } - ConstValue returnVal; - if (!constant) { - handleReference(ref, opcode == opc_invokevirtual - || opcode == opc_invokeinterface); - int retsize = TypeSignature.getTypeSize(retType); - returnVal = unknownValue[retsize - 1]; - } else { - info.constInfo = new ConstantInfo(CONSTANT, methodResult); - returnVal = new ConstValue(methodResult); - returnVal.addConstantListener(info.constInfo); - if (clsValue != null) - clsValue.addConstantListener(returnVal); - for (int i=0; i< argValues.length; i++) - argValues[i].addConstantListener(returnVal); - } - mergeInfo(instr.getNextByAddr(), info.poppush(size, returnVal)); - break; - } - - case opc_new: { - handleClass(instr.getClazzType()); - mergeInfo(instr.getNextByAddr(), info.poppush(0, unknownValue[0])); - break; - } - case opc_arraylength: { -// ConstValue array = info.getStack(1); -// if (array.value != ConstValue.VOLATILE -// && array.value != null) { -// Integer newValue = new Integer(Array.getLength(array.value)); -// info.constInfo = new ConstantInfo(CONSTANT, newValue); -// result = new ConstValue(newValue); -// result.addConstantListener(info.constInfo); -// array.addConstantListener(result); -// } else - result = unknownValue[0]; - mergeInfo(instr.getNextByAddr(), info.poppush(1, result)); - break; - } - case opc_checkcast: { - handleClass(instr.getClazzType()); - mergeInfo(instr.getNextByAddr(), info.pop(0)); - break; - } - case opc_instanceof: { - handleClass(instr.getClazzType()); - mergeInfo(instr.getNextByAddr(), info.poppush(1, unknownValue[0])); - break; - } - case opc_monitorenter: - case opc_monitorexit: - mergeInfo(instr.getNextByAddr(), info.pop(1)); - break; - case opc_multianewarray: - handleClass(instr.getClazzType()); - mergeInfo(instr.getNextByAddr(), - info.poppush(instr.getDimensions(), unknownValue[0])); - break; - default: - throw new IllegalArgumentException("Invalid opcode "+opcode); - } - } - - public void fieldNotConstant(FieldIdentifier fi) { - 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(); - if (ref.getName().equals(fi.getName()) - && ref.getType().equals(fi.getType()) - && instr.getTmpInfo() != null) { - ((StackLocalInfo) instr.getTmpInfo()).enqueue(); - } - } - } - } - - public void dumpStackLocalInfo() { - for (Iterator iter = bytecode.getInstructions().iterator(); - iter.hasNext(); ) { - Instruction instr = (Instruction) iter.next(); - System.err.println(""+instr.getTmpInfo()); - System.err.println(instr.getDescription()); - } - } - - public void analyzeCode(MethodIdentifier methodIdent, - BytecodeInfo bytecode) { - this.bytecode = bytecode; - TodoQueue modifiedQueue = new TodoQueue(); - MethodInfo minfo = bytecode.getMethodInfo(); - - for (Iterator iter = bytecode.getInstructions().iterator(); - iter.hasNext(); ) { - Instruction instr = (Instruction) iter.next(); - instr.setTmpInfo(null); - } - - StackLocalInfo firstInfo = new StackLocalInfo - (bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(), - modifiedQueue); - firstInfo.instr = (Instruction) bytecode.getInstructions().get(0); - firstInfo.instr.setTmpInfo(firstInfo); - firstInfo.enqueue(); - while (modifiedQueue.first != null) { - StackLocalInfo info = modifiedQueue.first; - modifiedQueue.first = info.nextOnQueue; - info.nextOnQueue = null; - handleOpcode(info, methodIdent); - } - - Handler[] handlers = bytecode.getExceptionHandlers(); - for (int i=0; i< handlers.length; i++) { - if (handlers[i].catcher.getTmpInfo() != null - && handlers[i].type != null) - Main.getClassBundle().reachableClass(handlers[i].type); - } - for (Iterator iter = bytecode.getInstructions().iterator(); - iter.hasNext(); ) { - Instruction instr = (Instruction) iter.next(); - StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo(); - if (info != null) { - if (info.constInfo.flags == 0) - instr.setTmpInfo(unknownConstInfo); - else - instr.setTmpInfo(info.constInfo); - } - } - } - - 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: - 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: - 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: - 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: - iter.set(new Instruction(opc_pop2)); - /* fall through */ - case opc_fcmpg: case opc_fcmpl: - case opc_l2i: case opc_l2f: case opc_l2d: - case opc_d2i: case opc_d2l: case opc_d2f: - case opc_lneg: case opc_dneg: - 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_iaload: case opc_laload: - case opc_faload: case opc_daload: case opc_aaload: - case opc_baload: case opc_caload: case opc_saload: - iter.set(new Instruction(opc_pop2)); - break; - - case opc_lshl: case opc_lshr: case opc_lushr: - iter.set(new Instruction(opc_pop2)); - iter.add(new Instruction(opc_pop)); - break; - case opc_putstatic: - case opc_putfield: - if (TypeSignature - .getTypeSize(instr.getReference().getType()) == 2) { - iter.set(new Instruction(opc_pop2)); - if (instr.getOpcode() == opc_putfield) - iter.add(new Instruction(opc_pop)); - } else - iter.set(new Instruction(instr.getOpcode() == opc_putfield - ? opc_pop2 : opc_pop)); - break; - case opc_invokespecial: - case opc_invokestatic: - case opc_invokeinterface: - case opc_invokevirtual: { - Reference ref = instr.getReference(); - String[] pt = TypeSignature.getParameterTypes(ref.getType()); - int arg = 0; - if (instr.getOpcode() != opc_invokestatic) - iter.set(new Instruction(opc_pop)); - else if (pt.length > 0) { - iter.set(new Instruction(TypeSignature.getTypeSize(pt[0]) - + 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(TypeSignature.getTypeSize(pt[i]) - + opc_pop - 1)); - } - } - if (replacement != null) - iter.add(replacement); - } - - public void appendJump(ListIterator iter, Instruction dest) { - /* Add a goto instruction after this opcode. */ - Instruction gotoInstr = new Instruction(Instruction.opc_goto); - gotoInstr.setSuccs(dest); - iter.add(gotoInstr); - } - - public void transformCode(BytecodeInfo bytecode) { - for (ListIterator iter = bytecode.getInstructions().listIterator(); - iter.hasNext(); ) { - Instruction instr = (Instruction) iter.next(); - ConstantInfo info = (ConstantInfo) instr.getTmpInfo(); - instr.setTmpInfo(null); - - if (info == null - || (info.flags & (RETURNINGJSR | RETASTORE)) == RETASTORE) { - /* This instruction can't be reached logically, or - * it is a return value astore, that should be removed */ - iter.remove(); - } else if ((info.flags & CONSTANT) != 0) { - if (instr.getOpcode() > opc_ldc2_w) { - 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 - + " with constant " + info.constant); - } - } else if ((info.flags & CONSTANTFLOW) != 0) { - Instruction pc = (Instruction) info.constant; - if (instr.getOpcode() >= opc_if_icmpeq - && instr.getOpcode() <= opc_if_acmpne) - iter.set(new Instruction(opc_pop2)); - else - iter.set(new Instruction(opc_pop)); - if (GlobalOptions.verboseLevel > 2) - GlobalOptions.err.println - (bytecode + ": Replacing " + instr - + " with goto " + pc.getAddr()); - while (iter.hasNext()) { - ConstantInfo nextinfo = (ConstantInfo) - ((Instruction) iter.next()).getTmpInfo(); - if (nextinfo != null) { - Instruction nextInstr = (Instruction) iter.previous(); - if (pc != nextInstr) - appendJump(iter, pc); - break; - } - /* Next instruction can't be reached logically */ - iter.remove(); - } - - } else { - int opcode = instr.getOpcode(); - switch (opcode) { - case opc_nop: - 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: - case opc_ifgt: case opc_ifle: - case opc_ifnull: case opc_ifnonnull: - 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: - - while (iter.hasNext()) { - ConstantInfo nextinfo = (ConstantInfo) - ((Instruction) iter.next()).getTmpInfo(); - if (nextinfo != null - && ((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 be removed */ - iter.remove(); - } - break; - - case opc_putstatic: - case opc_putfield: { - Reference ref = instr.getReference(); - FieldIdentifier fi = (FieldIdentifier) - Main.getClassBundle().getIdentifier(ref); - if (fi != null - && (Main.stripping & Main.STRIP_UNREACH) != 0 - && !fi.isReachable()) { - replaceWith(iter, instr, null); - } - break; - } - } - } - } - } -} diff --git a/jode/jode/obfuscator/FieldIdentifier.java.in b/jode/jode/obfuscator/FieldIdentifier.java.in index 74ea015..e552cd4 100644 --- a/jode/jode/obfuscator/FieldIdentifier.java.in +++ b/jode/jode/obfuscator/FieldIdentifier.java.in @@ -60,6 +60,11 @@ public class FieldIdentifier extends Identifier{ Main.getClassBundle().analyzeIdentifier(this); } + public void setSinglePreserved() { + super.setSinglePreserved(); + setNotConstant(); + } + public void analyze() { String type = getType(); int index = type.indexOf('L'); @@ -91,6 +96,10 @@ public class FieldIdentifier extends Identifier{ return type; } + public int getModifiers() { + return info.getModifiers(); + } + public Iterator getChilds() { return Collections.EMPTY_LIST.iterator(); } diff --git a/jode/jode/obfuscator/Identifier.java.in b/jode/jode/obfuscator/Identifier.java.in index e9ac883..0763acf 100644 --- a/jode/jode/obfuscator/Identifier.java.in +++ b/jode/jode/obfuscator/Identifier.java.in @@ -226,7 +226,11 @@ public abstract class Identifier { if (preserveRule.matches(this)) { System.err.println("preserving: "+this); setReachable(); - setPreserved(); + Identifier ident = this; + while (ident != null) { + ident.setPreserved(); + ident = ident.getParent(); + } } for (Iterator i = getChilds(); i.hasNext(); ) ((Identifier)i.next()).applyPreserveRule(preserveRule); diff --git a/jode/jode/obfuscator/LocalOptimizer.java.in b/jode/jode/obfuscator/LocalOptimizer.java.in deleted file mode 100644 index 3b6ca21..0000000 --- a/jode/jode/obfuscator/LocalOptimizer.java.in +++ /dev/null @@ -1,940 +0,0 @@ -/* LocalOptimizer 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 java.util.*; -import jode.bytecode.*; -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. - * - * This class can only work on verified code. There should also be no - * deadcode, since the verifier doesn't check that deadcode behaves - * okay. - * - * This is done in two phases. First we determine which locals are - * the same, and which locals have a overlapping life time. In the - * second phase we will then redistribute the locals with a coloring - * graph algorithm. - * - * The idea for the first phase is: For each read we follow the - * instruction flow backward to find the corresponding writes. We can - * also merge with another control flow that has a different read, in - * this case we merge with that read, too. - * - * The tricky part is the subroutine handling. We follow the local - * that is used in a ret and find the corresponding jsr target (there - * must be only one, if the verifier should accept this class). While - * we do this we remember in the info of the ret, which locals are - * used in that subroutine. - * - * When we know the jsr target<->ret correlation, we promote from the - * nextByAddr of every jsr the locals that are accessed by the - * subroutine to the corresponding ret and the others to the jsr. Also - * we will promote all reads from the jsr targets to the jsr. - * - * If you think this might be to complicated, keep in mind that jsr's - * are not only left by the ret instructions, but also "spontanously" - * (by not reading the return address again). - */ -public class LocalOptimizer implements Opcodes, CodeTransformer { - - /** - * This class keeps track of which locals must be the same, which - * name and type each local (if there is a local variable table) and - * which other locals have an intersecting life time. - */ - class LocalInfo { - LocalInfo shadow = null; - - public LocalInfo getReal() { - LocalInfo real = this; - while (real.shadow != null) - real = real.shadow; - return real; - } - - String name; - String type; - Vector usingInstrs = new Vector(); - Vector conflictingLocals = new Vector(); - int size; - int newSlot = -1; - - LocalInfo() { - } - - 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; - if (shadow.name == null) { - shadow.name = name; - shadow.type = type; - } - Enumeration enum = usingInstrs.elements(); - while (enum.hasMoreElements()) { - InstrInfo instr = (InstrInfo) enum.nextElement(); - instr.local = l; - l.usingInstrs.addElement(instr); - } - } - - public int getFirstAddr() { - int minAddr = Integer.MAX_VALUE; - Enumeration enum = usingInstrs.elements(); - while (enum.hasMoreElements()) { - InstrInfo info = (InstrInfo) enum.nextElement(); - if (info.instr.getAddr() < minAddr) - minAddr = info.instr.getAddr(); - } - return minAddr; - } - } - - private static class TodoQueue { - public final InstrInfo LAST = new InstrInfo(); - InstrInfo first = LAST; - - public void add(InstrInfo info) { - if (info.nextTodo == null) { - /* only enqueue if not already on queue */ - info.nextTodo = first; - first = info; - } - } - - public boolean isEmpty() { - return first == LAST; - } - - public InstrInfo remove() { - if (first == LAST) - throw new NoSuchElementException(); - InstrInfo result = first; - first = result.nextTodo; - result.nextTodo = null; - return result; - } - } - - - /** - * This class contains information for each instruction. - */ - static class InstrInfo { - /** - * The next changed InstrInfo, or null, if this instr info did - * not changed. - */ - InstrInfo nextTodo; - - /** - * The LocalInfo that this instruction manipulates, or null - * if this is not an ret, iinc, load or store instruction. - */ - LocalInfo local; - /** - * For each slot, this contains the InstrInfo of one of the - * next Instruction, that may read from that slot, without - * prior writing. */ - InstrInfo[] nextReads; - - /** - * This only has a value for ret instructions. In that case - * this bitset contains all locals, that may be used between - * jsr and ret. - */ - BitSet usedBySub; - /** - * For each slot if get() is true, no instruction may read - * this slot, since it may contain different locals, depending - * on flow. - */ - LocalInfo[] lifeLocals; - /** - * If instruction is the destination of a jsr, this contains - * the single allowed ret instruction info, or null if there - * is no ret at all (or not yet detected). - */ - InstrInfo retInfo; - /** - * If this instruction is a ret, this contains the single - * allowed jsr target to which this ret belongs. - */ - InstrInfo jsrTargetInfo; - /** - * The Instruction of this info - */ - Instruction instr; - /** - * The next info in the chain. - */ - InstrInfo nextInfo; - } - - BytecodeInfo bc; - - TodoQueue changedInfos; - InstrInfo firstInfo; - Hashtable instrInfos; - boolean produceLVT; - int maxlocals; - - LocalInfo[] paramLocals; - - public LocalOptimizer() { - } - - - /** - * Merges the given vector to a new vector. Both vectors may - * be null in which case they are interpreted as empty vectors. - * The vectors will never changed, but the result may be one - * of the given vectors. - */ - Vector merge(Vector v1, Vector v2) { - if (v1 == null || v1.isEmpty()) - return v2; - if (v2 == null || v2.isEmpty()) - return v1; - Vector result = (Vector) v1.clone(); - Enumeration enum = v2.elements(); - while (enum.hasMoreElements()) { - Object elem = enum.nextElement(); - if (!result.contains(elem)) - result.addElement(elem); - } - return result; - } - - void promoteReads(InstrInfo info, Instruction preInstr, - BitSet mergeSet, boolean inverted) { - InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr); - int omitLocal = -1; - if (preInstr.getOpcode() >= opc_istore - && preInstr.getOpcode() <= opc_astore) { - /* This is a store */ - omitLocal = preInstr.getLocalSlot(); - 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 - && (mergeSet == null || mergeSet.get(i) != inverted)) { - - if (preInfo.nextReads[i] == null) { - preInfo.nextReads[i] = info.nextReads[i]; - changedInfos.add(preInfo); - } else { - preInfo.nextReads[i].local - .combineInto(info.nextReads[i].local); - } - } - } - } - - void promoteReads(InstrInfo info, Instruction preInstr) { - promoteReads(info, preInstr, null, false); - } - - public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt, - int slot, int addr) { - LocalVariableInfo match = null; - for (int i=0; i < lvt.length; i++) { - if (lvt[i].slot == slot - && lvt[i].start.getAddr() <= addr - && lvt[i].end.getAddr() >= addr) { - if (match != null - && (!match.name.equals(lvt[i].name) - || !match.type.equals(lvt[i].type))) { - /* Multiple matches..., give no info */ - return null; - } - match = lvt[i]; - } - } - return match; - } - - public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt, - Instruction instr) { - int addr; - if (instr.getOpcode() >= opc_istore - && instr.getOpcode() <= opc_astore) - addr = instr.getNextAddr(); - else - addr = instr.getAddr(); - return findLVTEntry(lvt, instr.getLocalSlot(), addr); - } - - public void calcLocalInfo() { - maxlocals = bc.getMaxLocals(); - Handler[] handlers = bc.getExceptionHandlers(); - LocalVariableInfo[] lvt = bc.getLocalVariableTable(); - if (lvt != null) - produceLVT = true; - - /* Initialize paramLocals */ - { - 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()) { - LocalInfo local = new LocalInfo(); - if (lvt != null) { - LocalVariableInfo lvi = findLVTEntry(lvt, 0, 0); - if (lvi != null) { - local.name = lvi.name; - local.type = lvi.type; - } - } - local.size = 1; - paramLocals[slot++] = local; - } - int pos = 1; - while (pos < methodType.length() - && methodType.charAt(pos) != ')') { - - LocalInfo local = new LocalInfo(); - if (lvt != null) { - LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0); - if (lvi != null) { - local.name = lvi.name; - } - } - - 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; - } - } - - /* Initialize the InstrInfos and LocalInfos - */ - changedInfos = new TodoQueue(); - instrInfos = new Hashtable(); - { - InstrInfo info = firstInfo = new InstrInfo(); - 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.hasLocalSlot()) { - info.local = new LocalInfo(info); - if (lvt != null) { - LocalVariableInfo lvi = findLVTEntry(lvt, instr); - if (lvi != null) { - info.local.name = lvi.name; - info.local.type = lvi.type; - } - } - info.local.size = 1; - switch (instr.getOpcode()) { - case opc_lload: case opc_dload: - info.local.size = 2; - /* fall through */ - case opc_iload: case opc_fload: case opc_aload: - case opc_iinc: - /* this is a load instruction */ - info.nextReads[instr.getLocalSlot()] = info; - changedInfos.add(info); - break; - - case opc_ret: - /* this is a ret instruction */ - info.usedBySub = new BitSet(); - info.nextReads[instr.getLocalSlot()] = info; - changedInfos.add(info); - break; - - case opc_lstore: case opc_dstore: - info.local.size = 2; - //case opc_istore: case opc_fstore: case opc_astore: - } - } - if (!i.hasNext()) - break; - info = info.nextInfo = new InstrInfo(); - } - } - - /* find out which locals are the same. - */ - while (!changedInfos.isEmpty()) { - InstrInfo info = changedInfos.remove(); - Instruction instr = info.instr; - - /* Mark the local as used in all ret instructions */ - 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(slot)) { - retInfo.usedBySub.set(slot); - if (retInfo.jsrTargetInfo != null) - changedInfos.add(retInfo.jsrTargetInfo); - } - } - } - - Instruction prevInstr = instr.getPrevByAddr(); - if (prevInstr != null) { - if (!prevInstr.doesAlwaysJump()) - promoteReads(info, prevInstr); - else if (prevInstr.getOpcode() == opc_jsr) { - /* Prev instr is a jsr, promote reads to the - * corresponding ret. - */ - InstrInfo jsrInfo = - (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 - * to the jsr instruction. - */ - promoteReads(info, jsrInfo.retInfo.instr, - jsrInfo.retInfo.usedBySub, false); - promoteReads(info, prevInstr, - jsrInfo.retInfo.usedBySub, true); - } - } - } - - if (instr.getPreds() != null) { - for (int i = 0; i < instr.getPreds().length; i++) { - Instruction predInstr = instr.getPreds()[i]; - if (instr.getPreds()[i].getOpcode() == opc_jsr) { - /* This is the target of a jsr instr. - */ - if (info.instr.getOpcode() != opc_astore) { - /* XXX Grrr, the bytecode verifier doesn't - * test if a jsr starts with astore. So - * it is possible to do something else - * before putting the ret address into a - * local. */ - throw new AssertError("Non standard jsr"); - } - InstrInfo retInfo = info.nextInfo.nextReads - [info.instr.getLocalSlot()]; - - if (retInfo != null) { - if (retInfo.instr.getOpcode() != opc_ret) - throw new AssertError - ("reading return address"); - - info.retInfo = retInfo; - retInfo.jsrTargetInfo = info; - - /* Now promote reads from the instruction - * after the jsr to the ret instruction if - * they are modified by the subroutine, - * and to the jsr instruction otherwise. - */ - Instruction nextInstr = predInstr.getNextByAddr(); - InstrInfo nextInfo - = (InstrInfo) instrInfos.get(nextInstr); - - promoteReads(nextInfo, retInfo.instr, - retInfo.usedBySub, false); - - promoteReads(nextInfo, predInstr, - retInfo.usedBySub, true); - } - } - promoteReads(info, instr.getPreds()[i]); - } - } - - for (int i=0; i < handlers.length; i++) { - if (handlers[i].catcher == instr) { - for (Instruction preInstr = handlers[i].start; - preInstr != handlers[i].end.getNextByAddr(); - preInstr = preInstr.getNextByAddr()) { - promoteReads(info, preInstr); - } - } - } - } - changedInfos = null; - - /* Now merge with the parameters - * The params should be the locals in firstInfo.nextReads - */ - for (int i=0; i< paramLocals.length; i++) { - if (firstInfo.nextReads[i] != null) { - firstInfo.nextReads[i].local.combineInto(paramLocals[i]); - paramLocals[i] = paramLocals[i].getReal(); - } - } - } - - 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 (instr.getOpcode()) { - case opc_istore: - case opc_fstore: - case opc_astore: - iter.set(new Instruction(opc_pop)); - break; - case opc_lstore: - case opc_dstore: - iter.set(new Instruction(opc_pop2)); - break; - default: - } - } - } - } - - 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()) { - LocalInfo conflLocal = (LocalInfo)conflenum.nextElement(); - if (bestLocal.size == 2 && conflLocal.newSlot == slot+1) { - slot++; - continue next_slot; - } - if (conflLocal.size == 2 && conflLocal.newSlot+1 == slot) - continue next_slot; - if (conflLocal.newSlot == slot) { - if (conflLocal.size == 2) - 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). - */ - - /* first give the params the same slot as they had before. - */ - for (int i=0; i= 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. - * - * If this is inside a ret, it also conflicts with - * locals, that are not used inside, and where any jsr - * would conflict with. - */ - for (int i=0; i < maxlocals; i++) { - if (i != info.instr.getLocalSlot() - && info.nextReads[i] != null) - info.local.conflictsWith(info.nextReads[i].local); - if (info.nextInfo.nextReads[i] != null - && info.nextInfo.nextReads[i].jsrTargetInfo != null) { - Instruction[] jsrs = info.nextInfo.nextReads[i] - .jsrTargetInfo.instr.getPreds(); - for (int j=0; j< jsrs.length; j++) { - InstrInfo jsrInfo - = (InstrInfo) instrInfos.get(jsrs[j]); - for (int k=0; k < maxlocals; k++) { - if (!info.nextInfo.nextReads[i].usedBySub - .get(k) - && jsrInfo.nextReads[k] != null) - info.local.conflictsWith - (jsrInfo.nextReads[k].local); - } - } - } - } - } - } - - /* 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 and calculate new maxlocals. - */ - maxlocals = paramLocals.length; - for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { - if (info.local != null) { - if (info.local.newSlot+info.local.size > maxlocals) - maxlocals = info.local.newSlot + info.local.size; - info.instr.setLocalSlot(info.local.newSlot); - } - } - bc.setMaxLocals(maxlocals); - - /* Update LocalVariableTable - */ - if (produceLVT) - buildNewLVT(); - } - - private InstrInfo CONFLICT = new InstrInfo(); - - boolean promoteLifeLocals(LocalInfo[] newLife, InstrInfo nextInfo) { - if (nextInfo.lifeLocals == null) { - nextInfo.lifeLocals = (LocalInfo[]) newLife.clone(); - return true; - } - boolean changed = false; - for (int i=0; i< maxlocals; i++) { - LocalInfo local = nextInfo.lifeLocals[i]; - if (local == null) - /* A conflict has already happened, or this slot - * may not have been initialized. */ - continue; - - local = local.getReal(); - LocalInfo newLocal = newLife[i]; - if (newLocal != null) - newLocal = newLocal.getReal(); - if (local != newLocal) { - nextInfo.lifeLocals[i] = null; - changed = true; - } - } - return changed; - } - - public void buildNewLVT() { - /* First we recalculate the usedBySub, to use the new local numbers. - */ - for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) - if (info.usedBySub != null) - info.usedBySub = new BitSet(); - for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { - if (info.local != null) { - for (int i=0; i < info.nextReads.length; i++) { - if (info.nextReads[i] != null - && info.nextReads[i].instr.getOpcode() == opc_ret) - info.nextReads[i].usedBySub.set(info.local.newSlot); - } - } - } - - /* Now we begin with the first Instruction and follow program flow. - * We remember which locals are life in lifeLocals. - */ - - firstInfo.lifeLocals = new LocalInfo[maxlocals]; - for (int i=0; i < paramLocals.length; i++) - firstInfo.lifeLocals[i] = paramLocals[i]; - - Stack changedInfo = new Stack(); - changedInfo.push(firstInfo); - Handler[] handlers = bc.getExceptionHandlers(); - while (!changedInfo.isEmpty()) { - InstrInfo info = (InstrInfo) changedInfo.pop(); - Instruction instr = info.instr; - LocalInfo[] newLife = info.lifeLocals; - if (instr.hasLocalSlot()) { - int slot = instr.getLocalSlot(); - LocalInfo instrLocal = info.local.getReal(); - newLife = (LocalInfo[]) newLife.clone(); - newLife[slot] = instrLocal; - if (instrLocal.name != null) { - for (int j=0; j< newLife.length; j++) { - if (j != slot - && newLife[j] != null - && instrLocal.name.equals(newLife[j].name)) { - /* This local changed the slot. */ - newLife[j] = null; - } - } - } - } - - if (!instr.doesAlwaysJump()) { - InstrInfo nextInfo = info.nextInfo; - if (promoteLifeLocals(newLife, nextInfo)) - changedInfo.push(nextInfo); - } - if (instr.hasSuccs()) { - Instruction[] succs = instr.getSuccs(); - for (int i = 0; i < succs.length; i++) { - InstrInfo nextInfo - = (InstrInfo) instrInfos.get(succs[i]); - if (promoteLifeLocals(newLife, nextInfo)) - changedInfo.push(nextInfo); - } - } - for (int i=0; i < handlers.length; i++) { - 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)) - changedInfo.push(nextInfo); - } - } - - if (info.instr.getOpcode() == opc_jsr) { - /* On a jsr we do a special merge */ - - Instruction jsrTargetInstr = info.instr.getSingleSucc(); - InstrInfo jsrTargetInfo - = (InstrInfo) instrInfos.get(jsrTargetInstr); - InstrInfo retInfo = jsrTargetInfo.retInfo; - if (retInfo != null && retInfo.lifeLocals != null) { - LocalInfo[] retLife = (LocalInfo[]) newLife.clone(); - for (int i=0; i< maxlocals; i++) { - if (retInfo.usedBySub.get(i)) - retLife[i] = retInfo.lifeLocals[i]; - } - if (promoteLifeLocals(retLife, info.nextInfo)) - changedInfo.push(info.nextInfo); - } - } - - if (info.jsrTargetInfo != null) { - /* On a ret we do a special merge */ - - Instruction jsrTargetInstr = info.jsrTargetInfo.instr; - for (int j=0; j< jsrTargetInstr.getPreds().length; j++) { - InstrInfo jsrInfo - = (InstrInfo) instrInfos.get(jsrTargetInstr.getPreds()[j]); - - if (jsrInfo.lifeLocals == null) - /* life locals are not calculated, yet */ - continue; - LocalInfo[] retLife = (LocalInfo[]) newLife.clone(); - for (int i=0; i< maxlocals; i++) { - if (!info.usedBySub.get(i)) - retLife[i] = jsrInfo.lifeLocals[i]; - } - if (promoteLifeLocals(retLife, jsrInfo.nextInfo)) - changedInfo.push(jsrInfo.nextInfo); - } - } - } - - Vector lvtEntries = new Vector(); - LocalVariableInfo[] lvi = new LocalVariableInfo[maxlocals]; - LocalInfo[] currentLocal = new LocalInfo[maxlocals]; - for (int i=0; i< paramLocals.length; i++) { - if (paramLocals[i] != null) { - currentLocal[i] = paramLocals[i]; - if (currentLocal[i].name != null) { - lvi[i] = new LocalVariableInfo(); - lvtEntries.addElement(lvi[i]); - lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */ - lvi[i].type = Main.getClassBundle() - .getTypeAlias(currentLocal[i].type); - lvi[i].start = (Instruction) bc.getInstructions().get(0); - lvi[i].slot = i; - } - } - } - Instruction lastInstr = null; - for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { - for (int i=0; i< maxlocals; i++) { - LocalInfo lcl = info.lifeLocals != null ? info.lifeLocals[i] - : null; - if (lcl != currentLocal[i] - && (lcl == null || currentLocal[i] == null - || lcl.name == null || lcl.type == null - || !lcl.name.equals(currentLocal[i].name) - || !lcl.type.equals(currentLocal[i].type))) { - if (lvi[i] != null) { - lvi[i].end = info.instr.getPrevByAddr(); - } - lvi[i] = null; - currentLocal[i] = lcl; - if (currentLocal[i] != null - && currentLocal[i].name != null - && currentLocal[i].type != null) { - lvi[i] = new LocalVariableInfo(); - lvtEntries.addElement(lvi[i]); - lvi[i].name = currentLocal[i].name; - lvi[i].type = Main.getClassBundle() - .getTypeAlias(currentLocal[i].type); - lvi[i].start = info.instr; - lvi[i].slot = i; - } - } - } - lastInstr = info.instr; - } - for (int i=0; i< maxlocals; i++) { - if (lvi[i] != null) - lvi[i].end = lastInstr; - } - LocalVariableInfo[] lvt = new LocalVariableInfo[lvtEntries.size()]; - lvtEntries.copyInto(lvt); - bc.setLocalVariableTable(lvt); - } - - public void dumpLocals() { - Vector locals = new Vector(); - for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { - GlobalOptions.err.println(info.instr.getDescription()); - GlobalOptions.err.print("nextReads: "); - for (int i=0; i 0) - i.next(); - return (String) i.next(); - } - - public void remove() { - throw new UnsupportedOperationException(); - } - } - - public final Collection getCollection(Identifier ident) { - if (ident instanceof PackageIdentifier) - return packs; - else if (ident instanceof ClassIdentifier) - return clazzes; - else if (ident instanceof MethodIdentifier) - return methods; - else if (ident instanceof FieldIdentifier) - return fields; - else if (ident instanceof LocalIdentifier) - return locals; - else - throw new IllegalArgumentException(ident.getClass().getName()); - } - - public final void addIdentifierName(Identifier ident) { - getCollection(ident).add(ident.getName()); - } - - public Iterator generateNames(Identifier ident) { - return new NameGenerator(getCollection(ident)); - } -} - - diff --git a/jode/jode/obfuscator/PackageIdentifier.java.in b/jode/jode/obfuscator/PackageIdentifier.java.in index 3381779..7eb43e4 100644 --- a/jode/jode/obfuscator/PackageIdentifier.java.in +++ b/jode/jode/obfuscator/PackageIdentifier.java.in @@ -32,6 +32,8 @@ import java.util.zip.ZipOutputStream; import @COLLECTIONS@.Map; import @COLLECTIONS@.HashMap; import @COLLECTIONS@.Iterator; +import @COLLECTIONS@.List; +import @COLLECTIONS@.ArrayList; public class PackageIdentifier extends Identifier { ClassBundle bundle; @@ -248,8 +250,9 @@ public class PackageIdentifier extends Identifier { } } } - for (Iterator i = loadedClasses.values().iterator(); - i.hasNext(); ) { + List list = new ArrayList(); + list.addAll(loadedClasses.values()); + for (Iterator i = list.iterator(); i.hasNext(); ) { Identifier ident = (Identifier) i.next(); if (ident instanceof PackageIdentifier) { if (matcher.matches(ident)) diff --git a/jode/jode/obfuscator/RemovePopAnalyzer.java.in b/jode/jode/obfuscator/RemovePopAnalyzer.java.in deleted file mode 100644 index cab6778..0000000 --- a/jode/jode/obfuscator/RemovePopAnalyzer.java.in +++ /dev/null @@ -1,307 +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; - -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 21dd15c..3204ffb 100644 --- a/jode/jode/obfuscator/ScriptParser.java.in +++ b/jode/jode/obfuscator/ScriptParser.java.in @@ -204,7 +204,8 @@ public class ScriptParser { throw new ParseException(linenr, "Class name expected"); Object instance; try { - Class clazz = Class.forName("jode.obfuscator."+scanner.getValue()); + Class clazz = Class.forName("jode.obfuscator.modules." + +scanner.getValue()); instance = clazz.newInstance(); } catch (ClassNotFoundException ex) { throw new ParseException(scanner.getLineNr(), diff --git a/jode/jode/obfuscator/SimpleAnalyzer.java.in b/jode/jode/obfuscator/SimpleAnalyzer.java.in deleted file mode 100644 index 844d82f..0000000 --- a/jode/jode/obfuscator/SimpleAnalyzer.java.in +++ /dev/null @@ -1,182 +0,0 @@ -/* SimpleAnalyzer 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.Handler; -import jode.bytecode.Opcodes; -import jode.bytecode.ClassInfo; -import jode.bytecode.BytecodeInfo; -import jode.bytecode.Instruction; -import jode.bytecode.Reference; -import jode.bytecode.TypeSignature; -import jode.GlobalOptions; - -import @COLLECTIONS@.Iterator; -import @COLLECTIONS@.ListIterator; - -public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { - - public Identifier canonizeReference(Instruction instr) { - Reference ref = instr.getReference(); - Identifier ident = Main.getClassBundle().getIdentifier(ref); - String clName = ref.getClazz(); - String realClazzName; - if (ident != null) { - ClassIdentifier clazz = (ClassIdentifier)ident.getParent(); - realClazzName = "L" + (clazz.getFullName() - .replace('.', '/')) + ";"; - } else { - /* We have to look at the ClassInfo's instead, to - * point to the right method. - */ - ClassInfo clazz; - if (clName.charAt(0) == '[') { - /* Arrays don't define new methods (well clone(), - * but that can be ignored). - */ - clazz = ClassInfo.javaLangObject; - } else { - clazz = ClassInfo.forName - (clName.substring(1, clName.length()-1) - .replace('/','.')); - } - if (instr.getOpcode() >= opc_invokevirtual) { - while (clazz != null - && clazz.findMethod(ref.getName(), - ref.getType()) == null) - clazz = clazz.getSuperclass(); - } else { - while (clazz != null - && clazz.findField(ref.getName(), - ref.getType()) == null) - clazz = clazz.getSuperclass(); - } - - if (clazz == null) { - GlobalOptions.err.println("WARNING: Can't find reference: " - +ref); - realClazzName = clName; - } else - realClazzName = "L" + clazz.getName().replace('.', '/') + ";"; - } - if (!realClazzName.equals(ref.getClazz())) { - ref = Reference.getReference(realClazzName, - ref.getName(), ref.getType()); - instr.setReference(ref); - } - return ident; - } - - - /** - * Reads the opcodes out of the code info and determine its - * references - * @return an enumeration of the references. - */ - public void analyzeCode(MethodIdentifier m, BytecodeInfo bytecode) { - for (Iterator iter = bytecode.getInstructions().iterator(); - iter.hasNext(); ) { - Instruction instr = (Instruction) iter.next(); - switch (instr.getOpcode()) { - case opc_checkcast: - case opc_instanceof: - case opc_multianewarray: { - String clName = instr.getClazzType(); - int i = 0; - while (i < clName.length() && clName.charAt(i) == '[') - i++; - if (i < clName.length() && clName.charAt(i) == 'L') { - clName = clName.substring(i+1, clName.length()-1) - .replace('/','.'); - Main.getClassBundle().reachableClass(clName); - } - break; - } - case opc_invokespecial: - case opc_invokestatic: - case opc_invokeinterface: - case opc_invokevirtual: - case opc_putstatic: - case opc_putfield: - m.setGlobalSideEffects(); - /* fall through */ - case opc_getstatic: - case opc_getfield: { - Identifier ident = canonizeReference(instr); - if (ident != null) { - if (instr.getOpcode() == opc_putstatic - || instr.getOpcode() == opc_putfield) { - FieldIdentifier fi = (FieldIdentifier) ident; - if (fi != null && !fi.isNotConstant()) - fi.setNotConstant(); - } else if (instr.getOpcode() == opc_invokevirtual - || instr.getOpcode() == opc_invokeinterface) { - ((ClassIdentifier) ident.getParent()) - .reachableReference(instr.getReference(), true); - } else { - ident.setReachable(); - } - } - break; - } - } - } - - Handler[] handlers = bytecode.getExceptionHandlers(); - for (int i=0; i< handlers.length; i++) { - if (handlers[i].type != null) - Main.getClassBundle() - .reachableClass(handlers[i].type); - } - } - - public void transformCode(BytecodeInfo bytecode) { - 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(); - FieldIdentifier fi = (FieldIdentifier) - Main.getClassBundle().getIdentifier(ref); - if (fi != null - && (Main.stripping & Main.STRIP_UNREACH) != 0 - && !fi.isReachable()) { - /* Replace instruction with pop opcodes. */ - int stacksize = - (instr.getOpcode() - == Instruction.opc_putstatic) ? 0 : 1; - stacksize += TypeSignature.getTypeSize(ref.getType()); - 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; - } - } - } - } - } -} diff --git a/jode/jode/obfuscator/StrongRenamer.java.in b/jode/jode/obfuscator/StrongRenamer.java.in deleted file mode 100644 index 6d6a00d..0000000 --- a/jode/jode/obfuscator/StrongRenamer.java.in +++ /dev/null @@ -1,141 +0,0 @@ -/* StrongRenamer 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 @COLLECTIONS@.Collection; -import @COLLECTIONS@.Iterator; -import @COLLECTIONEXTRA@.UnsupportedOperationException; - -public class StrongRenamer implements Renamer, OptionHandler { - static String[] idents = { - "Package", "Class", "Field", "Method", "Local" - }; - static String[] parts = { - "Start", "Part" - }; - String charsets[][]; - - public StrongRenamer() { - charsets = new String[idents.length][parts.length]; - for (int i=0; i< idents.length; i++) - for (int j=0; j< parts.length; j++) - charsets[i][j] = "abcdefghijklmnopqrstuvwxyz"; - } - - public void setOption(String option, Collection values) { - if (option.startsWith("charset")) { - Object value = values.iterator().next(); - if (values.size() != 1 || !(value instanceof String)) - throw new IllegalArgumentException - ("Only string parameter are supported."); - String set = (String) value; - String remOpt = option.substring("charset".length()); - int part = -1, ident = -1; - if (remOpt.length() > 0) { - for (int i=0; i < idents.length; i++) { - if (remOpt.startsWith(idents[i])) { - remOpt = option.substring(idents[i].length()); - ident = i; - break; - } - } - } - if (remOpt.length() > 0) { - for (int j=0; j < parts.length; j++) { - if (remOpt.startsWith(parts[j])) { - remOpt = option.substring(parts[j].length()); - part = j; - break; - } - } - } - if (remOpt.length() > 0) - throw new IllegalArgumentException("Invalid charset `" - +option+"'"); - for (int i = 0; i < idents.length; i++) { - if (ident >= 0 && ident != i) - continue; - for (int j = 0; j < parts.length; j++) { - if (part >= 0 && part != j) - continue; - charsets[i][j] = set; - } - } - } else - throw new IllegalArgumentException("Invalid option `" - +option+"'"); - } - - public Iterator generateNames(Identifier ident) { - final String[] currCharset; - if (ident instanceof PackageIdentifier) - currCharset = charsets[0]; - else if (ident instanceof PackageIdentifier) - currCharset = charsets[1]; - else if (ident instanceof ClassIdentifier) - currCharset = charsets[2]; - else if (ident instanceof FieldIdentifier) - currCharset = charsets[3]; - else if (ident instanceof MethodIdentifier) - currCharset = charsets[4]; - else if (ident instanceof LocalIdentifier) - currCharset = charsets[5]; - else - throw new IllegalArgumentException(ident.getClass().getName()); - - return new Iterator() { - char[] name = null; - - public boolean hasNext() { - return true; - } - public Object next() { - if (name == null) { - name = new char[] { currCharset[0].charAt(0) }; - return new String(name); - } - - int pos = name.length - 1; - String charset = currCharset[1]; - while (pos >= 0) { - if (pos == 0) - charset = currCharset[0]; - - int index = charset.indexOf(name[pos]) + 1; - if (index < charset.length()) { - name[pos] = charset.charAt(index); - return new String(name); - } - name[pos--] = charset.charAt(0); - } - - name = new char[name.length+1]; - name[0] = currCharset[0].charAt(0); - char firstCont = currCharset[1].charAt(0); - for (int i=1; i 0) - prefix += "."; - - int lastDot = prefix.length(); - if (!wildcard.startsWith(prefix)) - return null; - - int nextDot = wildcard.indexOf('.', lastDot); - if (nextDot > 0 - && (nextDot <= firstStar || firstStar == -1)) - return wildcard.substring(lastDot, nextDot); - else if (firstStar == -1) - return wildcard.substring(lastDot); - else - return null; - } - - public boolean matchesSub(Identifier ident, String subident) { - String prefix = ident.getFullName(); - if (prefix.length() > 0) - prefix += "."; - if (subident != null) - prefix += subident; - if (firstStar == -1 || firstStar >= prefix.length()) - return wildcard.startsWith(prefix); - return prefix.startsWith(wildcard.substring(0, firstStar)); - } - - public boolean matches(Identifier ident) { - String test = ident.getFullName(); - if (firstStar == -1) { - if (wildcard.equals(test)) { - return true; - } - return false; - } - if (!test.startsWith(wildcard.substring(0, firstStar))) - return false; - - test = test.substring(firstStar); - int lastWild = firstStar; - int nextWild; - while ((nextWild = wildcard.indexOf('*', lastWild + 1)) != -1) { - String pattern = wildcard.substring(lastWild+1, nextWild); - while (!test.startsWith(pattern)) { - if (test.length() == 0) - return false; - test = test.substring(1); - } - test = test.substring(nextWild - lastWild - 1); - lastWild = nextWild; - } - - return test.endsWith(wildcard.substring(lastWild+1)); - } - - public String toString() { - return "Wildcard "+wildcard; - } -}