instructions now collectionified

Use listIterator to manipulate bytecode
Some bug fixes
More use of TypeSignature, and prevent using of jode.type.Type


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1097 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent dcd5686bc2
commit c3ead8b084
  1. 154
      jode/jode/obfuscator/ClassBundle.java.in
  2. 34
      jode/jode/obfuscator/ClassIdentifier.java.in
  3. 226
      jode/jode/obfuscator/ConstantAnalyzer.java.in
  4. 24
      jode/jode/obfuscator/FieldIdentifier.java.in
  5. 97
      jode/jode/obfuscator/LocalOptimizer.java.in
  6. 0
      jode/jode/obfuscator/LocalizeFieldTransformer.java.in
  7. 1
      jode/jode/obfuscator/Makefile.am
  8. 24
      jode/jode/obfuscator/MethodIdentifier.java.in
  9. 77
      jode/jode/obfuscator/PackageIdentifier.java.in
  10. 262
      jode/jode/obfuscator/RemovePopAnalyzer.java
  11. 307
      jode/jode/obfuscator/RemovePopAnalyzer.java.in
  12. 4
      jode/jode/obfuscator/ScriptParser.java.in
  13. 40
      jode/jode/obfuscator/SimpleAnalyzer.java.in
  14. 1
      jode/jode/obfuscator/UniqueRenamer.java.in

@ -99,6 +99,21 @@ public class ClassBundle implements OptionHandler {
return;
}
if (option.equals("table")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Only one destination path allowed");
tableFile = (String) values.iterator().next();
return;
}
if (option.equals("revtable")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Only one destination path allowed");
toTableFile = (String) values.iterator().next();
return;
}
if (option.equals("strip")) {
next_token:
for (Iterator iter = values.iterator(); iter.hasNext(); ) {
@ -116,33 +131,72 @@ public class ClassBundle implements OptionHandler {
}
if (option.equals("load")) {
if (values.size() == 1)
loading = (IdentifierMatcher) values.iterator().next();
else
if (values.size() == 1) {
Object value = values.iterator().next();
if (value instanceof String)
loading = new WildCard((String)value);
else
loading = (IdentifierMatcher) value;
} else {
IdentifierMatcher[] matchers
= new IdentifierMatcher[values.size()];
int j = 0;
for (Iterator i = values.iterator(); i.hasNext(); ) {
Object value = i.next();
matchers[j++] = (value instanceof String
? new WildCard((String)value)
: (IdentifierMatcher) value);
}
loading = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, (IdentifierMatcher[])
values.toArray(new IdentifierMatcher[values.size()]));
(MultiIdentifierMatcher.OR, matchers);
}
return;
}
if (option.equals("preserve")) {
if (values.size() == 1)
preserving = (IdentifierMatcher) values.iterator().next();
else
if (values.size() == 1) {
Object value = values.iterator().next();
if (value instanceof String)
preserving = new WildCard((String)value);
else
preserving = (IdentifierMatcher) value;
} else {
IdentifierMatcher[] matchers
= new IdentifierMatcher[values.size()];
int j = 0;
for (Iterator i = values.iterator(); i.hasNext(); ) {
Object value = i.next();
matchers[j++] = (value instanceof String
? new WildCard((String)value)
: (IdentifierMatcher) value);
}
preserving = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, (IdentifierMatcher[])
values.toArray(new IdentifierMatcher[values.size()]));
(MultiIdentifierMatcher.OR, matchers);
}
return;
}
if (option.equals("reach")) {
// NOT IMPLEMENTED YET
if (values.size() == 1)
reaching = (IdentifierMatcher) values.iterator().next();
else
if (values.size() == 1) {
Object value = values.iterator().next();
if (value instanceof String)
reaching = new WildCard((String)value);
else
reaching = (IdentifierMatcher) value;
} else {
IdentifierMatcher[] matchers
= new IdentifierMatcher[values.size()];
int j = 0;
for (Iterator i = values.iterator(); i.hasNext(); ) {
Object value = i.next();
matchers[j++] = (value instanceof String
? new WildCard((String)value)
: (IdentifierMatcher) value);
}
reaching = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, (IdentifierMatcher[])
values.toArray(new IdentifierMatcher[values.size()]));
(MultiIdentifierMatcher.OR, matchers);
}
}
if (option.equals("pre")) {
@ -228,8 +282,22 @@ public class ClassBundle implements OptionHandler {
return ident.getIdentifier(ref.getName(), ref.getType());
}
public void reachableIdentifier(String fqn, boolean isVirtual) {
basePackage.reachableIdentifier(fqn, isVirtual);
public void reachableClass(String clazzName) {
ClassIdentifier ident = getClassIdentifier(clazzName);
if (ident != null)
ident.setReachable();
}
public void reachableReference(Reference ref, boolean isVirtual) {
String clName = ref.getClazz();
if (clName.charAt(0) == '[')
/* Can't represent arrays */
return;
ClassIdentifier ident =
getClassIdentifier(clName.substring(1, clName.length()-1)
.replace('/','.'));
if (ident != null)
ident.reachableReference(ref, isVirtual);
}
public void analyzeIdentifier(Identifier ident) {
@ -340,7 +408,7 @@ public class ClassBundle implements OptionHandler {
}
public Object next() {
return (last++ == 1 ? base : base + last);
return (last++ == 0 ? base : base + last);
}
public void remove() {
@ -349,24 +417,72 @@ public class ClassBundle implements OptionHandler {
};
}
};
Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory();
long last;
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used before: "+(runtime.totalMemory()- free));
GlobalOptions.err.println("Loading and preserving classes");
long time = System.currentTimeMillis();
basePackage.loadMatchingClasses(loading);
basePackage.applyPreserveRule(preserving);
System.err.println("Time used: "+(System.currentTimeMillis() - time));
GlobalOptions.err.println("Computing reachable settings");
time = System.currentTimeMillis();
analyze();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
free = runtime.freeMemory();
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used after analyze: "
+ (runtime.totalMemory() - free));
GlobalOptions.err.println("Renaming methods");
time = System.currentTimeMillis();
if (tableFile != null)
readTable();
buildTable(renamer);
if (toTableFile != null)
writeTable();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
GlobalOptions.err.println("Transforming the classes");
time = System.currentTimeMillis();
doTransformations();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
free = runtime.freeMemory();
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used after transform: "
+ (runtime.totalMemory() - free));
GlobalOptions.err.println("Writing new classes");
time = System.currentTimeMillis();
storeClasses();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
}
}

@ -60,10 +60,8 @@ public class ClassIdentifier extends Identifier {
public void addSubClass(ClassIdentifier ci) {
knownSubClasses.add(ci);
for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) {
String[] method = (String[]) i.next();
ci.reachableIdentifier(method[0], method[1], true);
}
for(Iterator i = virtualReachables.iterator(); i.hasNext(); )
ci.reachableReference((Reference) i.next(), true);
}
private FieldIdentifier findField(String name, String typeSig) {
@ -86,13 +84,12 @@ public class ClassIdentifier extends Identifier {
return null;
}
public void reachableIdentifier(String name, String typeSig,
boolean isVirtual) {
public void reachableReference(Reference ref, boolean isVirtual) {
boolean found = false;
for (Iterator i = getChilds(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (name.equals(ident.getName())
&& typeSig.equals(ident.getType())) {
if (ref.getName().equals(ident.getName())
&& ref.getType().equals(ident.getType())) {
ident.setReachable();
found = true;
}
@ -108,14 +105,21 @@ public class ClassIdentifier extends Identifier {
ClassIdentifier superIdent = Main.getClassBundle()
.getClassIdentifier(info.getSuperclass().getName());
if (superIdent != null)
superIdent.reachableIdentifier(name, typeSig, false);
superIdent.reachableReference(ref, false);
}
if (isVirtual) {
for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) {
Reference prevRef = (Reference) i.next();
if (prevRef.getName().equals(ref.getName())
&& prevRef.getType().equals(ref.getType()))
// already handled.
return;
}
for (Iterator i = knownSubClasses.iterator(); i.hasNext(); )
((ClassIdentifier)i.next())
.reachableIdentifier(name, typeSig, false);
virtualReachables.add(new String[] { name, typeSig });
.reachableReference(ref, false);
virtualReachables.add(ref);
}
}
@ -308,14 +312,18 @@ public class ClassIdentifier extends Identifier {
superident.addSubClass(this);
} else {
// all virtual methods in superclass are reachable now!
String clazzType = ("L"+superclass.getName().replace('.', '/')
+";").intern();
MethodInfo[] topmethods = superclass.getMethods();
for (int i=0; i< topmethods.length; i++) {
int modif = topmethods[i].getModifiers();
if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
& modif) == 0
&& !topmethods[i].getName().equals("<init>")) {
reachableIdentifier
(topmethods[i].getName(), topmethods[i].getType(),
reachableReference
(Reference.getReference(clazzType,
topmethods[i].getName(),
topmethods[i].getType()),
true);
}
}

@ -38,6 +38,7 @@ import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashMap;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
/**
* Analyze the code, assuming every field that is not yet written to
@ -464,13 +465,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
}
public void handleReference(Reference ref, boolean isVirtual) {
String clName = ref.getClazz();
/* Don't have to reach array methods */
if (clName.charAt(0) != '[') {
clName = clName.substring(1, clName.length()-1).replace('/', '.');
Main.getClassBundle().reachableIdentifier
(clName+"."+ref.getName()+"."+ref.getType(), isVirtual);
}
Main.getClassBundle().reachableReference(ref, isVirtual);
}
public void handleClass(String clName) {
@ -479,7 +474,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
i++;
if (i < clName.length() && clName.charAt(i) == 'L') {
clName = clName.substring(i+1, clName.length()-1);
Main.getClassBundle().reachableIdentifier(clName, false);
Main.getClassBundle().reachableClass(clName);
}
}
@ -872,7 +867,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
if (local.value != ConstValue.VOLATILE) {
result = new ConstValue
(new Integer(((Integer)local.value).intValue()
+ instr.getIntData()));
+ instr.getIncrement()));
local.addConstantListener(result);
} else
result = unknownValue[0];
@ -1072,7 +1067,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
}
if ((opc_mask & (1<<opcode)) != 0)
pc = instr.getSuccs()[0];
pc = instr.getSingleSucc();
ConstantInfo shortInfo = new ConstantInfo();
constInfos.put(instr, shortInfo);
@ -1081,40 +1076,19 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
mergeInfo(pc, info.pop(size));
} else {
mergeInfo(instr.getNextByAddr(), info.pop(size));
mergeInfo(instr.getSuccs()[0], info.pop(size));
mergeInfo(instr.getSingleSucc(), info.pop(size));
}
break;
}
case opc_goto:
mergeInfo(instr.getSuccs()[0], info.copy());
mergeInfo(instr.getSingleSucc(), info.copy());
break;
case opc_jsr:
mergeInfo(instr.getSuccs()[0],
mergeInfo(instr.getSingleSucc(),
info.poppush(0, new ConstValue
(new JSRTargetInfo(instr.getSuccs()[0]))));
(new JSRTargetInfo(instr.getSingleSucc()))
));
break;
case opc_tableswitch: {
ConstValue stacktop = info.getStack(1);
if (stacktop.value != ConstValue.VOLATILE) {
stacktop.addConstantListener(info);
Instruction pc;
int value = ((Integer) stacktop.value).intValue();
int low = instr.getIntData();
if (value >= low && value <= low + instr.getSuccs().length - 2)
pc = instr.getSuccs()[value - low];
else
pc = instr.getSuccs()[instr.getSuccs().length-1];
ConstantInfo shortInfo = new ConstantInfo();
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANTFLOW;
shortInfo.constant = pc;
mergeInfo(pc, info.pop(1));
} else {
for (int i=0; i < instr.getSuccs().length; i++)
mergeInfo(instr.getSuccs()[i], info.pop(1));
}
break;
}
case opc_lookupswitch: {
ConstValue stacktop = info.getStack(1);
if (stacktop.value != ConstValue.VOLATILE) {
@ -1264,15 +1238,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
constant = false;
if (jode.GlobalOptions.verboseLevel > 3)
GlobalOptions.err.println("Can't interpret "+ref+": "
+ ex.getMessage());
+ ex.getMessage());
/* result is not constant */
} catch (InvocationTargetException ex) {
constant = false;
if (jode.GlobalOptions.verboseLevel > 3)
GlobalOptions.err.println("Method "+ref
+" throwed exception: "
+ ex.getTargetException()
.getMessage());
+" throwed exception: "
+ ex.getTargetException());
/* method always throws exception ? */
}
}
@ -1333,7 +1306,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_multianewarray:
handleClass(instr.getClazzType());
mergeInfo(instr.getNextByAddr(),
info.poppush(instr.getIntData(), unknownValue[0]));
info.poppush(instr.getDimensions(), unknownValue[0]));
break;
default:
throw new jode.AssertError("Invalid opcode "+opcode);
@ -1342,8 +1315,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
}
public void fieldNotConstant(FieldIdentifier fi) {
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.getNextByAddr()) {
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getfield
|| instr.getOpcode() == opc_getstatic) {
Reference ref = instr.getReference();
@ -1357,8 +1331,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
}
public void dumpStackLocalInfo() {
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.getNextByAddr()) {
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo();
System.err.println(""+info);
System.err.println(instr.getDescription());
@ -1375,7 +1350,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
StackLocalInfo firstInfo = new StackLocalInfo
(bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(),
modifiedQueue);
firstInfo.instr = bytecode.getFirstInstr();
firstInfo.instr = (Instruction) bytecode.getInstructions().get(0);
firstInfo.instr.setTmpInfo(firstInfo);
modifiedQueue.add(firstInfo);
while (!modifiedQueue.isEmpty()) {
@ -1389,35 +1364,43 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
for (int i=0; i< handlers.length; i++) {
if (handlers[i].catcher.getTmpInfo() != null
&& handlers[i].type != null)
Main.getClassBundle().reachableIdentifier(handlers[i].type, false);
Main.getClassBundle().reachableClass(handlers[i].type);
}
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.getNextByAddr())
instr.setTmpInfo(null);
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); )
((Instruction) iter.next()).setTmpInfo(null);
}
public void insertOnePop(Instruction instr, int count) {
/* Add a goto instruction after this opcode. */
Instruction pop
= instr.insertInstruction(Instruction.opc_pop - 1 + count);
}
public void insertPop(Instruction instr) {
public static void replaceWith(ListIterator iter, Instruction instr,
Instruction replacement) {
switch(instr.getOpcode()) {
case opc_goto:
case opc_ldc:
case opc_ldc2_w:
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
case opc_getstatic:
break;
if (replacement == null)
iter.remove();
else
iter.set(replacement);
return;
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_ifnull: case opc_ifnonnull:
case opc_arraylength:
case opc_getfield:
case opc_i2l: case opc_i2f: case opc_i2d:
case opc_f2i: case opc_f2l: case opc_f2d:
case opc_i2b: case opc_i2c: case opc_i2s:
case opc_ineg: case opc_fneg:
insertOnePop(instr, 1);
iter.set(new Instruction(opc_pop));
break;
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_lcmp:
case opc_dcmpg: case opc_dcmpl:
case opc_ladd: case opc_dadd:
@ -1426,7 +1409,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_ldiv: case opc_ddiv:
case opc_lrem: case opc_drem:
case opc_land: case opc_lor : case opc_lxor:
insertOnePop(instr, 2);
iter.set(new Instruction(opc_pop2));
/* fall through */
case opc_fcmpg: case opc_fcmpl:
case opc_l2i: case opc_l2f: case opc_l2d:
@ -1442,22 +1425,23 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
insertOnePop(instr, 2);
iter.set(new Instruction(opc_pop2));
break;
case opc_lshl: case opc_lshr: case opc_lushr:
insertOnePop(instr, 1);
insertOnePop(instr, 2);
iter.set(new Instruction(opc_pop2));
iter.add(new Instruction(opc_pop));
break;
case opc_putstatic:
case opc_putfield:
if (Type.tType(instr.getReference().getType())
.stackSize() == 2) {
insertOnePop(instr, 2);
iter.set(new Instruction(opc_pop2));
if (instr.getOpcode() == opc_putfield)
insertOnePop(instr, 1);
iter.add(new Instruction(opc_pop));
} else
insertOnePop(instr, (instr.getOpcode() == opc_putfield) ? 2 : 1);
iter.set(new Instruction(instr.getOpcode() == opc_putfield
? opc_pop2 : opc_pop));
break;
case opc_invokespecial:
case opc_invokestatic:
@ -1465,34 +1449,52 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_invokevirtual: {
Reference ref = instr.getReference();
MethodType mt = (MethodType) Type.tType(ref.getType());
for (int i=mt.getParameterTypes().length-1; i >=0; i--)
insertOnePop(instr, mt.getParameterTypes()[i].stackSize());
Type[] pt = mt.getParameterTypes();
int arg = 0;
if (instr.getOpcode() != opc_invokestatic)
insertOnePop(instr, 1);
iter.set(new Instruction(opc_pop));
else if (pt.length > 0) {
iter.set(new Instruction(pt[0].stackSize() + opc_pop - 1));
arg++;
} else {
if (replacement == null)
iter.remove();
else
iter.set(replacement);
return;
}
for (int i=arg; i < pt.length; i++)
iter.add(new Instruction(pt[i].stackSize() + opc_pop - 1));
}
}
if (replacement != null)
iter.add(replacement);
}
public void appendJump(Instruction instr, Instruction dest) {
public void appendJump(ListIterator iter, Instruction dest) {
/* Add a goto instruction after this opcode. */
instr.appendInstruction(Instruction.opc_goto,
new Instruction[] { dest });
Instruction gotoInstr = new Instruction(Instruction.opc_goto);
gotoInstr.setSuccs(dest);
iter.add(gotoInstr);
}
public void transformCode(BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.getNextByAddr()) {
for (ListIterator iter = bytecode.getInstructions().listIterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
ConstantInfo info = (ConstantInfo) constInfos.get(instr);
if (info == null || (info.flags & REACHABLE) == 0) {
/* This instruction can't be reached logically */
instr.removeInstruction();
iter.remove();
} else if ((info.flags & CONSTANT) != 0) {
insertPop(instr);
if (instr.getOpcode() > opc_ldc2_w) {
instr.replaceInstruction(info.constant instanceof Long
|| info.constant instanceof Double
? opc_ldc2_w : opc_ldc);
instr.setConstant(info.constant);
Instruction ldcInstr
= new Instruction(info.constant instanceof Long
|| info.constant instanceof Double
? opc_ldc2_w : opc_ldc);
ldcInstr.setConstant(info.constant);
replaceWith(iter, instr, ldcInstr);
if (GlobalOptions.verboseLevel > 2)
GlobalOptions.err.println
(bytecode + ": Replacing " + instr
@ -1502,61 +1504,60 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
Instruction pc = (Instruction) info.constant;
if (instr.getOpcode() >= opc_if_icmpeq
&& instr.getOpcode() <= opc_if_acmpne)
instr.replaceInstruction(opc_pop2);
iter.set(new Instruction(opc_pop2));
else
instr.replaceInstruction(opc_pop);
iter.set(new Instruction(opc_pop));
if (GlobalOptions.verboseLevel > 2)
GlobalOptions.err.println
(bytecode + ": Replacing " + instr
+ " with goto " + pc.getAddr());
while (instr.getNextByAddr() != null) {
ConstantInfo nextinfo
= (ConstantInfo) constInfos.get(instr.getNextByAddr());
if (nextinfo != null && (nextinfo.flags & REACHABLE) != 0)
while (iter.hasNext()) {
ConstantInfo nextinfo = (ConstantInfo)
constInfos.get((Instruction) iter.next());
if (nextinfo != null
&& (nextinfo.flags & REACHABLE) != 0) {
Instruction nextInstr = (Instruction) iter.previous();
if (pc != nextInstr)
appendJump(iter, pc);
break;
}
/* Next instruction can't be reached logically */
instr.getNextByAddr().removeInstruction();
iter.remove();
}
if (pc != instr.getNextByAddr()) {
appendJump(instr, pc);
instr = instr.getNextByAddr();
}
} else {
int opcode = instr.getOpcode();
switch (opcode) {
case opc_nop:
instr.removeInstruction();
iter.remove();
break;
case opc_goto:
while (instr.getNextByAddr() != null) {
ConstantInfo nextinfo
= (ConstantInfo) constInfos.get(instr.getNextByAddr());
if (nextinfo != null
&& (nextinfo.flags & REACHABLE) != 0)
break;
/* Next instruction can't be reached logically */
instr.getNextByAddr().removeInstruction();
}
if (instr.getSuccs()[0] == instr.getNextByAddr())
instr.removeInstruction();
break;
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_ifnull: case opc_ifnonnull:
if (instr.getSuccs()[0] == instr.getNextByAddr())
instr.replaceInstruction(opc_pop);
break;
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
if (instr.getSuccs()[0] == instr.getNextByAddr())
instr.replaceInstruction(opc_pop2);
while (iter.hasNext()) {
ConstantInfo nextinfo = (ConstantInfo)
constInfos.get((Instruction) iter.next());
if (nextinfo != null
&& (nextinfo.flags & REACHABLE) != 0) {
Instruction nextInstr
= (Instruction) iter.previous();
if (instr.getSingleSucc() == nextInstr) {
iter.previous();
replaceWith(iter, instr, null);
}
break;
}
/* Next instruction can't be reached logically */
iter.remove();
}
break;
case opc_putstatic:
@ -1567,8 +1568,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
if (fi != null
&& (Main.stripping & Main.STRIP_UNREACH) != 0
&& !fi.isReachable()) {
insertPop(instr);
instr.removeInstruction();
replaceWith(iter, instr, null);
}
break;
}

@ -65,8 +65,8 @@ public class FieldIdentifier extends Identifier{
int index = type.indexOf('L');
if (index != -1) {
int end = type.indexOf(';', index);
Main.getClassBundle().reachableIdentifier
(type.substring(index+1, end), false);
Main.getClassBundle().reachableClass
(type.substring(index+1, end).replace('/', '.'));
}
}
@ -75,11 +75,12 @@ public class FieldIdentifier extends Identifier{
}
public String getFullName() {
return clazz.getFullName() + "." + getName();
return clazz.getFullName() + "." + getName() + "." + getType();
}
public String getFullAlias() {
return clazz.getFullAlias() + "." + getAlias();
return clazz.getFullAlias() + "." + getAlias() + "."
+ Main.getClassBundle().getTypeAlias(getType());
}
public String getName() {
@ -120,20 +121,7 @@ public class FieldIdentifier extends Identifier{
}
public String toString() {
return "FieldIdentifier "+getFullName()+"."+getType();
}
public void readTable(Map table) {
String alias = (String) table.get(getFullName() + "." + getType());
if (alias == null)
alias = (String) table.get(getFullName());
if (alias != null)
setAlias(alias);
}
public void writeTable(Map table) {
table.put(getFullAlias() + "."
+ Main.getClassBundle().getTypeAlias(getType()), getName());
return "FieldIdentifier "+getFullName();
}
public boolean conflicting(String newAlias) {

@ -20,10 +20,12 @@
package jode.obfuscator;
import java.util.*;
import jode.bytecode.*;
import jode.type.Type;
import jode.AssertError;
import jode.GlobalOptions;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
/**
* This class takes some bytecode and tries to minimize the number
* of locals used. It will also remove unnecessary stores.
@ -221,14 +223,12 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
BitSet mergeSet, boolean inverted) {
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr);
int omitLocal = -1;
if (preInstr.getLocalSlot() != -1
&& preInstr.getOpcode() >= opc_istore
if (preInstr.getOpcode() >= opc_istore
&& preInstr.getOpcode() <= opc_astore) {
/* This is a store */
omitLocal = preInstr.getLocalSlot();
if (info.nextReads[preInstr.getLocalSlot()] != null)
preInfo.local.combineInto
(info.nextReads[preInstr.getLocalSlot()].local);
if (info.nextReads[omitLocal] != null)
preInfo.local.combineInto(info.nextReads[omitLocal].local);
}
for (int i=0; i < maxlocals; i++) {
if (info.nextReads[i] != null && i != omitLocal
@ -270,10 +270,12 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
Instruction instr) {
int addr = instr.getAddr();
int addr;
if (instr.getOpcode() >= opc_istore
&& instr.getOpcode() <= opc_astore)
addr += instr.getLength();
addr = instr.getNextAddr();
else
addr = instr.getAddr();
return findLVTEntry(lvt, instr.getLocalSlot(), addr);
}
@ -286,11 +288,9 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
/* Initialize paramLocals */
{
int paramCount = bc.getMethodInfo().isStatic() ? 0 : 1;
Type[] paramTypes =
Type.tMethod(bc.getMethodInfo().getType()).getParameterTypes();
for (int i = paramTypes.length; i-- > 0;)
paramCount += paramTypes[i].stackSize();
String methodType = bc.getMethodInfo().getType();
int paramCount = (bc.getMethodInfo().isStatic() ? 0 : 1)
+ TypeSignature.getArgumentSize(methodType);
paramLocals = new LocalInfo[paramCount];
int slot = 0;
if (!bc.getMethodInfo().isStatic()) {
@ -305,7 +305,10 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
local.size = 1;
paramLocals[slot++] = local;
}
for (int i = 0; i< paramTypes.length; i++) {
int pos = 1;
while (pos < methodType.length()
&& methodType.charAt(pos) != ')') {
LocalInfo local = new LocalInfo();
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0);
@ -313,8 +316,11 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
local.name = lvi.name;
}
}
local.type = paramTypes[i].getTypeSignature();
local.size = paramTypes[i].stackSize();
int start = pos;
pos = TypeSignature.skipType(methodType, pos);
local.type = methodType.substring(start, pos);
local.size = TypeSignature.getTypeSize(local.type);
paramLocals[slot] = local;
slot += local.size;
}
@ -326,12 +332,13 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
instrInfos = new Hashtable();
{
InstrInfo info = firstInfo = new InstrInfo();
Instruction instr = bc.getFirstInstr();
Iterator i = bc.getInstructions().iterator();
while (true) {
Instruction instr = (Instruction) i.next();
instrInfos.put(instr, info);
info.instr = instr;
info.nextReads = new InstrInfo[maxlocals];
if (instr.getLocalSlot() != -1) {
if (instr.hasLocalSlot()) {
info.local = new LocalInfo(info);
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, instr);
@ -364,7 +371,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
//case opc_istore: case opc_fstore: case opc_astore:
}
}
if ((instr = instr.getNextByAddr()) == null)
if (!i.hasNext())
break;
info = info.nextInfo = new InstrInfo();
}
@ -377,16 +384,17 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
Instruction instr = info.instr;
/* Mark the local as used in all ret instructions */
if (instr.getLocalSlot() != -1) {
if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
for (int i=0; i< maxlocals; i++) {
InstrInfo retInfo = info.nextReads[i];
if (retInfo != null && retInfo.instr.getOpcode() == opc_ret
&& !retInfo.usedBySub.get(instr.getLocalSlot())) {
retInfo.usedBySub.set(instr.getLocalSlot());
if (retInfo != null
&& retInfo.instr.getOpcode() == opc_ret
&& !retInfo.usedBySub.get(slot)) {
retInfo.usedBySub.set(slot);
if (retInfo.jsrTargetInfo != null)
changedInfos.push(retInfo.jsrTargetInfo);
}
}
}
@ -397,7 +405,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
* corresponding ret.
*/
InstrInfo jsrInfo =
(InstrInfo) instrInfos.get(prevInstr.getSuccs()[0]);
(InstrInfo) instrInfos.get(prevInstr.getSingleSucc());
if (jsrInfo.retInfo != null) {
/* Now promote reads that are modified by the
* subroutine to the ret, and those that are not
@ -426,8 +434,8 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
* local. */
throw new AssertError("Non standard jsr");
}
InstrInfo retInfo
= info.nextInfo.nextReads[info.instr.getLocalSlot()];
InstrInfo retInfo = info.nextInfo.nextReads
[info.instr.getLocalSlot()];
if (retInfo != null) {
if (retInfo.instr.getOpcode() != opc_ret)
@ -481,21 +489,21 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
}
public void stripLocals() {
ListIterator iter = bc.getInstructions().listIterator();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
Instruction instr = (Instruction) iter.next();
if (info.local != null && info.local.usingInstrs.size() == 1) {
/* If this is a store, whose value is never read; it can
* be removed, i.e replaced by a pop. */
switch (info.instr.getOpcode()) {
switch (instr.getOpcode()) {
case opc_istore:
case opc_fstore:
case opc_astore:
info.local = null;
info.instr.replaceInstruction(opc_pop);
iter.set(new Instruction(opc_pop));
break;
case opc_lstore:
case opc_dstore:
info.local = null;
info.instr.replaceInstruction(opc_pop);
iter.set(new Instruction(opc_pop2));
break;
default:
}
@ -568,8 +576,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
/* Now calculate the conflict settings.
*/
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.instr.getLocalSlot() != -1
&& info.instr.getOpcode() >= BytecodeInfo.opc_istore
if (info.instr.getOpcode() >= BytecodeInfo.opc_istore
&& info.instr.getOpcode() <= BytecodeInfo.opc_astore) {
/* This is a store. It conflicts with every local, whose
* value will be read without write.
@ -692,13 +699,14 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
InstrInfo info = (InstrInfo) changedInfo.pop();
Instruction instr = info.instr;
LocalInfo[] newLife = info.lifeLocals;
if (instr.getLocalSlot() != -1) {
if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
LocalInfo instrLocal = info.local.getReal();
newLife = (LocalInfo[]) newLife.clone();
newLife[instr.getLocalSlot()] = instrLocal;
newLife[slot] = instrLocal;
if (instrLocal.name != null) {
for (int j=0; j< newLife.length; j++) {
if (j != instr.getLocalSlot()
if (j != slot
&& newLife[j] != null
&& instrLocal.name.equals(newLife[j].name)) {
/* This local changed the slot. */
@ -713,17 +721,18 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
if (instr.getSuccs() != null) {
for (int i = 0; i < instr.getSuccs().length; i++) {
if (instr.hasSuccs()) {
Instruction[] succs = instr.getSuccs();
for (int i = 0; i < succs.length; i++) {
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(instr.getSuccs()[i]);
= (InstrInfo) instrInfos.get(succs[i]);
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
}
for (int i=0; i < handlers.length; i++) {
if (handlers[i].start.getAddr() <= instr.getAddr()
&& handlers[i].end.getAddr() >= instr.getAddr()) {
if (handlers[i].start.compareTo(instr) <= 0
&& handlers[i].end.compareTo(instr) >= 0) {
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(handlers[i].catcher);
if (promoteLifeLocals(newLife, nextInfo))
@ -734,7 +743,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
if (info.instr.getOpcode() == opc_jsr) {
/* On a jsr we do a special merge */
Instruction jsrTargetInstr = info.instr.getSuccs()[0];
Instruction jsrTargetInstr = info.instr.getSingleSucc();
InstrInfo jsrTargetInfo
= (InstrInfo) instrInfos.get(jsrTargetInstr);
InstrInfo retInfo = jsrTargetInfo.retInfo;
@ -783,7 +792,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */
lvi[i].type = Main.getClassBundle()
.getTypeAlias(currentLocal[i].type);
lvi[i].start = bc.getFirstInstr();
lvi[i].start = (Instruction) bc.getInstructions().get(0);
lvi[i].slot = i;
}
}

@ -34,6 +34,7 @@ MY_JAVA_FILES = \
SimpleAnalyzer.java \
StrongRenamer.java \
TranslationTable.java \
UniqueRenamer.java \
WildCard.java
# LocalizeFieldTransformer.java

@ -88,9 +88,8 @@ public class MethodIdentifier extends Identifier implements Opcodes {
int index = type.indexOf('L');
while (index != -1) {
int end = type.indexOf(';', index);
Main.getClassBundle()
.reachableIdentifier(type.substring(index+1, end)
, false);
Main.getClassBundle().reachableClass
(type.substring(index+1, end).replace('/', '.'));
index = type.indexOf('L', end);
}
@ -98,7 +97,7 @@ public class MethodIdentifier extends Identifier implements Opcodes {
if (exceptions != null) {
for (int i=0; i< exceptions.length; i++)
Main.getClassBundle()
.reachableIdentifier(exceptions[i], false);
.reachableClass(exceptions[i]);
}
BytecodeInfo code = info.getBytecode();
@ -106,14 +105,6 @@ public class MethodIdentifier extends Identifier implements Opcodes {
codeAnalyzer.analyzeCode(this, code);
}
public void readTable(Map table) {
setAlias((String) table.get(getFullName() + "." + getType()));
}
public void writeTable(Map table) {
table.put(getFullAlias(), getName());
}
public Identifier getParent() {
return clazz;
}
@ -140,7 +131,7 @@ public class MethodIdentifier extends Identifier implements Opcodes {
}
public String toString() {
return "MethodIdentifier "+getFullName()+"."+getType();
return "MethodIdentifier "+getFullName();
}
public boolean hasGlobalSideEffects() {
@ -187,9 +178,10 @@ public class MethodIdentifier extends Identifier implements Opcodes {
ex.printStackTrace(GlobalOptions.err);
bytecode.dumpCode(GlobalOptions.err);
}
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.getNextByAddr()) {
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
switch (instr.getOpcode()) {
case opc_invokespecial:
case opc_invokestatic:

@ -64,44 +64,32 @@ public class PackageIdentifier extends Identifier {
return;
loadOnDemand = true;
if ((Main.stripping & Main.STRIP_UNREACH) == 0) {
String fullname = getFullName();
if (fullname.length() > 0)
fullname += ".";
// Load all classes and packages now, so they don't get stripped
Vector v = new Vector();
Enumeration enum =
ClassInfo.getClassesAndPackages(getFullName());
while (enum.hasMoreElements()) {
//insert sorted and remove double elements;
String subclazz = (String)enum.nextElement();
for (int i=0; ; i++) {
if (i == v.size()) {
v.addElement(subclazz);
break;
}
int compare = subclazz.compareTo((String)v.elementAt(i));
if (compare < 0) {
v.insertElementAt(subclazz, i);
break;
} else if (compare == 0)
break;
}
}
enum = v.elements();
while (enum.hasMoreElements()) {
String subclazz = (String) enum.nextElement();
String fullname = getFullName();
fullname = (fullname.length() > 0)
? fullname + "."+ subclazz
: subclazz;
if (ClassInfo.isPackage(fullname)) {
String subclazz = ((String)enum.nextElement()).intern();
if (loadedClasses.containsKey(subclazz))
continue;
String subFull = fullname + subclazz;
if (ClassInfo.isPackage(subFull)) {
PackageIdentifier ident = new PackageIdentifier
(bundle, this, subclazz);
loadedClasses.put(subclazz, ident);
ident.setLoadOnDemand();
} else {
Identifier ident = new ClassIdentifier
(this, subclazz, ClassInfo.forName(fullname));
ClassIdentifier ident = new ClassIdentifier
(this, subclazz, ClassInfo.forName(subFull));
if (GlobalOptions.verboseLevel > 1)
GlobalOptions.err.println("preloading Class "
+ subFull);
loadedClasses.put(subclazz, ident);
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("preloading "+ident);
((ClassIdentifier) ident).initClass();
}
}
@ -184,6 +172,7 @@ public class PackageIdentifier extends Identifier {
if (component != null) {
Identifier ident = (Identifier) loadedClasses.get(component);
if (ident == null) {
component = component.intern();
String fullname = getFullName();
fullname = (fullname.length() > 0)
? fullname + "." + component
@ -227,7 +216,7 @@ public class PackageIdentifier extends Identifier {
Enumeration enum =
ClassInfo.getClassesAndPackages(getFullName());
while (enum.hasMoreElements()) {
String subclazz = (String)enum.nextElement();
String subclazz = ((String)enum.nextElement()).intern();
if (loadedClasses.containsKey(subclazz))
continue;
String subFull = fullname + subclazz;
@ -276,36 +265,6 @@ public class PackageIdentifier extends Identifier {
loadMatchingClasses(preserveRule);
super.applyPreserveRule(preserveRule);
}
public void reachableIdentifier(String fqn, boolean isVirtual) {
int index = fqn.indexOf('.');
String component = index == -1 ? fqn : fqn.substring(0, index);
Identifier ident = getIdentifier(component);
if (ident == null)
return;
if (index == -1) {
ident.setReachable();
return;
}
if (ident instanceof PackageIdentifier)
((PackageIdentifier) ident).reachableIdentifier
(fqn.substring(index+1), isVirtual);
else {
String method = fqn.substring(index+1);
index = method.indexOf('.');
if (index == -1) {
((ClassIdentifier) ident).reachableIdentifier
(method, null, isVirtual);
} else {
((ClassIdentifier) ident).reachableIdentifier
(method.substring(0, index), method.substring(index+1),
isVirtual);
}
}
}
// public void preserveMatchingIdentifier(IdentifierMatcher matcher) {
// String component = matcher.getNextComponent(getFullName());
// if (component != null) {

@ -1,262 +0,0 @@
/* RemovePopAnalyzer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.*;
import jode.AssertError;
import jode.GlobalOptions;
public class RemovePopAnalyzer implements CodeTransformer, Opcodes {
public RemovePopAnalyzer() {
}
class PopInfo {
int firstPop = 0;
int[] pops;
Instruction nextInstr;
}
static Instruction shrinkPop(Instruction popInstr, int amount) {
int newPop = popInstr.getOpcode() - (opc_pop-1) - amount;
if (newPop < 0)
throw new jode.AssertError("pop1 on long or double");
if (newPop == 0) {
Instruction nextInstr = popInstr.getNextByAddr();
popInstr.removeInstruction();
return nextInstr;
}
popInstr.replaceInstruction(opc_pop - 1 + newPop);
return popInstr;
}
public void transformCode(BytecodeInfo bytecode) {
int poppush[] = new int[2];
Instruction instr = bytecode.getFirstInstr();
while (instr != null) {
switch (instr.getOpcode()) {
case opc_nop: {
Instruction nextInstr = instr.getNextByAddr();
instr.removeInstruction();
instr = nextInstr;
continue;
}
case opc_pop:
case opc_pop2: {
/* find push instruction */
int count = 0;
Instruction pushInstr = instr;
while (true) {
if (pushInstr.getPreds() != null) {
pushInstr = null;
break;
}
pushInstr = pushInstr.getPrevByAddr();
if (pushInstr == null
|| pushInstr.getSuccs() != null
|| pushInstr.doesAlwaysJump()) {
pushInstr = null;
break;
}
pushInstr.getStackPopPush(poppush);
if (count < poppush[1])
break;
count += poppush[0] - poppush[1];
}
int opcode = pushInstr == null ? -1 : pushInstr.getOpcode();
if (count > 0) {
/* If this is a dup and the instruction popped is the
* duplicated element, remove the dup
*/
if (count <= 2 && opcode == (opc_dup + count - 1)) {
pushInstr.removeInstruction();
instr = shrinkPop(instr, 1);
continue;
}
if (instr.getOpcode() == opc_pop2
&& count > 1 && count <= 3
&& opcode == (opc_dup2 + count-2)) {
pushInstr.removeInstruction();
instr = shrinkPop(instr, 2);
continue;
}
/* Otherwise popping is not possible */
opcode = -1;
}
switch (opcode) {
case opc_ldc2_w:
case opc_lload: case opc_dload:
pushInstr.removeInstruction();
instr = shrinkPop(instr, 2);
continue;
case opc_ldc:
case opc_iload: case opc_fload: case opc_aload:
case opc_dup:
case opc_new:
pushInstr.removeInstruction();
instr = shrinkPop(instr, 1);
continue;
case opc_iaload: case opc_faload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
/* We have to pop one entry more. */
pushInstr.replaceInstruction(opc_pop);
instr = pushInstr;
continue;
case opc_dup_x1:
pushInstr.replaceInstruction(opc_swap);
instr = shrinkPop(instr, 1);
continue;
case opc_dup2:
if (instr.getOpcode() == opc_pop2) {
pushInstr.removeInstruction();
instr = shrinkPop(instr, 2);
}
continue;
case opc_lneg: case opc_dneg:
case opc_l2d: case opc_d2l:
case opc_laload: case opc_daload:
if (instr.getOpcode() != opc_pop2)
break;
/* fall through */
case opc_ineg: case opc_fneg:
case opc_i2f: case opc_f2i:
case opc_i2b: case opc_i2c: case opc_i2s:
case opc_newarray: case opc_anewarray:
case opc_arraylength:
case opc_instanceof:
pushInstr.removeInstruction();
continue;
case opc_iadd: case opc_fadd:
case opc_isub: case opc_fsub:
case opc_imul: case opc_fmul:
case opc_idiv: case opc_fdiv:
case opc_irem: case opc_frem:
case opc_iand: case opc_ior : case opc_ixor:
case opc_ishl: case opc_ishr: case opc_iushr:
case opc_fcmpl: case opc_fcmpg:
case opc_l2i: case opc_l2f:
case opc_d2i: case opc_d2f:
pushInstr.replaceInstruction(opc_pop2);
shrinkPop(instr, 1);
instr = pushInstr;
continue;
case opc_ladd: case opc_dadd:
case opc_lsub: case opc_dsub:
case opc_lmul: case opc_dmul:
case opc_ldiv: case opc_ddiv:
case opc_lrem: case opc_drem:
case opc_land: case opc_lor : case opc_lxor:
if (instr.getOpcode() != opc_pop2)
break;
pushInstr.replaceInstruction(opc_pop2);
instr = pushInstr;
continue;
case opc_lshl: case opc_lshr: case opc_lushr:
if (instr.getOpcode() != opc_pop2)
break;
pushInstr.replaceInstruction(opc_pop);
instr = pushInstr;
continue;
case opc_i2l: case opc_i2d:
case opc_f2l: case opc_f2d:
if (instr.getOpcode() != opc_pop2)
break;
pushInstr.removeInstruction();
instr.replaceInstruction(opc_pop);
continue;
case opc_lcmp:
case opc_dcmpl: case opc_dcmpg:
pushInstr.replaceInstruction(opc_pop2);
if (instr.getOpcode() == opc_pop)
instr.replaceInstruction(opc_pop2);
else {
instr.appendInstruction(opc_pop);
}
instr = pushInstr;
continue;
case opc_getstatic:
case opc_getfield: {
Reference ref = pushInstr.getReference();
int size = TypeSignature.getTypeSize(ref.getType());
if (pushInstr.getOpcode() == opc_getfield)
size--;
pushInstr.removeInstruction();
if (size > 0)
instr = shrinkPop(instr, size);
continue;
}
case opc_multianewarray: {
int dims = pushInstr.getIntData();
pushInstr.removeInstruction();
if (dims == 0)
instr = shrinkPop(instr, 1);
else {
dims--;
while (dims > 0) {
instr = instr.insertInstruction(opc_pop);
dims--;
}
}
continue;
}
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
if (TypeSignature.getReturnSize
(pushInstr.getReference().getType()) != 1)
break;
/* fall through */
case opc_checkcast:
case -1:
if (instr.getOpcode() == opc_pop2) {
/* This is/may be a double pop on a single value
* split it and continue with second half
*/
instr.replaceInstruction(opc_pop);
instr = instr.appendInstruction(opc_pop);
continue;
}
}
if (instr.getOpcode() == opc_pop
&& instr.getPreds() == null
&& instr.getPrevByAddr().getOpcode() == opc_pop) {
/* merge two single pops together. */
instr.getPrevByAddr().removeInstruction();
instr.replaceInstruction(opc_pop2);
}
/* Cant do anything with this pop */
}
/* fall through */
default:
instr = instr.getNextByAddr();
continue;
}
}
}
}

@ -0,0 +1,307 @@
/* RemovePopAnalyzer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.*;
import jode.AssertError;
import jode.GlobalOptions;
import @COLLECTIONS@.ListIterator;
public class RemovePopAnalyzer implements CodeTransformer, Opcodes {
public RemovePopAnalyzer() {
}
public void transformCode(BytecodeInfo bytecode) {
int poppush[] = new int[2];
ListIterator iter = bytecode.getInstructions().listIterator();
next_pop:
while (iter.hasNext()) {
Instruction popInstr = (Instruction) iter.next();
boolean isPop2 = false;
switch (popInstr.getOpcode()) {
case opc_nop: {
iter.remove();
continue;
}
case opc_pop2:
isPop2 = true;
case opc_pop:
if (popInstr.getPreds() != null)
// Can't handle pop with multiple predecessors
continue next_pop;
Handler[] handlers = bytecode.getExceptionHandlers();
for (int i=0; i < handlers.length; i++)
if (handlers[i].catcher == popInstr)
continue next_pop;
// remove pop, we will insert it again if something
// bad happened.
iter.remove();
// remember position of pop, so we can insert it again.
Instruction popPrevious = (Instruction) iter.previous();
Instruction instr = popPrevious;
int count = 0;
while (true) {
if (instr.getSuccs() != null
|| instr.doesAlwaysJump()) {
instr = null;
break;
}
instr.getStackPopPush(poppush);
if (count < poppush[1]) {
if (count == 0)
break;
int opcode = instr.getOpcode();
/* If this is a dup and the instruction popped is the
* duplicated element, remove the dup and the pop
*/
if (count <= 3 && opcode == (opc_dup + count - 1)) {
iter.remove();
if (!isPop2)
continue next_pop;
// We have to consider a pop instead of a
// pop2 now.
popInstr = new Instruction(opc_pop);
isPop2 = false;
instr = (Instruction) iter.previous();
continue;
}
if (isPop2
&& count > 1 && count <= 4
&& opcode == (opc_dup2 + count-2)) {
iter.remove();
continue next_pop;
}
/* Otherwise popping is not possible */
instr = null;
break;
}
count += poppush[0] - poppush[1];
instr = (Instruction) iter.previous();
}
if (instr == null) {
// We insert the pop at the previous position
while (iter.next() != popPrevious)
{}
if (!isPop2 && popPrevious.getOpcode() == opc_pop) {
// merge pop with popPrevious
iter.set(new Instruction(opc_pop2));
} else
iter.add(popInstr);
continue;
}
int opcode = instr.getOpcode();
switch (opcode) {
case opc_ldc2_w:
case opc_lload: case opc_dload:
if (!isPop2)
throw new AssertError("pop on long");
iter.remove();
continue;
case opc_ldc:
case opc_iload: case opc_fload: case opc_aload:
case opc_dup:
case opc_new:
if (isPop2)
iter.set(new Instruction(opc_pop));
else
iter.remove();
continue;
case opc_iaload: case opc_faload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
case opc_iadd: case opc_fadd:
case opc_isub: case opc_fsub:
case opc_imul: case opc_fmul:
case opc_idiv: case opc_fdiv:
case opc_irem: case opc_frem:
case opc_iand: case opc_ior : case opc_ixor:
case opc_ishl: case opc_ishr: case opc_iushr:
case opc_fcmpl: case opc_fcmpg:
/* We have to pop one entry more. */
iter.next();
iter.add(popInstr);
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop));
continue;
case opc_dup_x1:
iter.set(new Instruction(opc_swap));
iter.next();
if (isPop2)
iter.add(new Instruction(opc_pop));
continue;
case opc_dup2:
if (isPop2) {
iter.remove();
continue;
}
break;
case opc_swap:
if (isPop2) {
iter.set(popInstr);
continue;
}
break;
case opc_lneg: case opc_dneg:
case opc_l2d: case opc_d2l:
case opc_laload: case opc_daload:
if (!isPop2)
throw new AssertError("pop on long");
/* fall through */
case opc_ineg: case opc_fneg:
case opc_i2f: case opc_f2i:
case opc_i2b: case opc_i2c: case opc_i2s:
case opc_newarray: case opc_anewarray:
case opc_arraylength:
case opc_instanceof:
iter.set(popInstr);
continue;
case opc_l2i: case opc_l2f:
case opc_d2i: case opc_d2f:
if (isPop2) {
iter.next();
iter.add(new Instruction(opc_pop));
iter.previous();
iter.previous();
}
iter.set(new Instruction(opc_pop2));
continue;
case opc_ladd: case opc_dadd:
case opc_lsub: case opc_dsub:
case opc_lmul: case opc_dmul:
case opc_ldiv: case opc_ddiv:
case opc_lrem: case opc_drem:
case opc_land: case opc_lor : case opc_lxor:
if (!isPop2)
throw new AssertError("pop on long");
iter.next();
iter.add(popInstr);
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop2));
continue;
case opc_lshl: case opc_lshr: case opc_lushr:
if (!isPop2)
throw new AssertError("pop on long");
iter.next();
iter.add(popInstr);
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop));
continue;
case opc_i2l: case opc_i2d:
case opc_f2l: case opc_f2d:
if (!isPop2)
throw new AssertError("pop on long");
iter.set(new Instruction(opc_pop));
continue;
case opc_lcmp:
case opc_dcmpl: case opc_dcmpg:
iter.next();
iter.add(new Instruction(opc_pop2));
if (isPop2) {
iter.add(new Instruction(opc_pop));
iter.previous();
}
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop2));
continue;
case opc_getstatic:
case opc_getfield: {
Reference ref = instr.getReference();
int size = TypeSignature.getTypeSize(ref.getType());
if (size == 2 && !isPop2)
throw new AssertError("pop on long");
if (opcode == opc_getfield)
size--;
switch (size) {
case 0:
iter.set(popInstr);
break;
case 1:
if (isPop2) {
iter.set(new Instruction(opc_pop));
break;
}
/* fall through */
case 2:
iter.remove();
}
continue;
}
case opc_multianewarray: {
int dims = instr.getDimensions();
if (--dims > 0) {
iter.next();
while (dims-- > 0) {
iter.add(new Instruction(opc_pop));
iter.previous();
}
iter.previous();
}
iter.set(popInstr);
continue;
}
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
if (TypeSignature.getReturnSize
(instr.getReference().getType()) != 1)
break;
/* fall through */
case opc_checkcast:
if (isPop2) {
/* This is/may be a double pop on a single value
* split it and continue with second half
*/
iter.next();
iter.add(new Instruction(opc_pop));
iter.add(new Instruction(opc_pop));
iter.previous();
continue;
}
}
// append the pop behind the unresolvable opcode.
iter.next();
iter.add(popInstr);
continue;
}
}
}
}

@ -251,7 +251,9 @@ public class ScriptParser {
} catch (RuntimeException ex) {
throw new ParseException(linenr,
optionHandler.getClass().getName()
+": Illegal value: "+ex.getMessage());
+": Illegal value: "
+ex.getClass().getName()
+": "+ex.getMessage());
}
}
}

@ -27,6 +27,9 @@ import jode.bytecode.Reference;
import jode.GlobalOptions;
import jode.type.Type;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
public Identifier canonizeReference(Instruction instr) {
@ -87,8 +90,9 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
* @return an enumeration of the references.
*/
public void analyzeCode(MethodIdentifier m, BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.getNextByAddr()) {
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
switch (instr.getOpcode()) {
case opc_checkcast:
case opc_instanceof:
@ -98,8 +102,9 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
while (i < clName.length() && clName.charAt(i) == '[')
i++;
if (i < clName.length() && clName.charAt(i) == 'L') {
clName = clName.substring(i+1, clName.length()-1);
Main.getClassBundle().reachableIdentifier(clName, false);
clName = clName.substring(i+1, clName.length()-1)
.replace('/','.');
Main.getClassBundle().reachableClass(clName);
}
break;
}
@ -123,8 +128,7 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
} else if (instr.getOpcode() == opc_invokevirtual
|| instr.getOpcode() == opc_invokeinterface) {
((ClassIdentifier) ident.getParent())
.reachableIdentifier(ident.getName(),
ident.getType(), true);
.reachableReference(instr.getReference(), true);
} else {
ident.setReachable();
}
@ -138,13 +142,14 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
for (int i=0; i< handlers.length; i++) {
if (handlers[i].type != null)
Main.getClassBundle()
.reachableIdentifier(handlers[i].type, false);
.reachableClass(handlers[i].type);
}
}
public void transformCode(BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.getNextByAddr()) {
for (ListIterator iter = bytecode.getInstructions().listIterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_putstatic
|| instr.getOpcode() == opc_putfield) {
Reference ref = instr.getReference();
@ -158,13 +163,18 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
(instr.getOpcode()
== Instruction.opc_putstatic) ? 0 : 1;
stacksize += Type.tType(ref.getType()).stackSize();
if (stacksize == 3) {
/* Add a pop instruction after this opcode. */
instr.appendInstruction(Instruction.opc_pop);
stacksize--;
switch (stacksize) {
case 1:
iter.set(new Instruction(Instruction.opc_pop));
break;
case 2:
iter.set(new Instruction(Instruction.opc_pop2));
break;
case 3:
iter.set(new Instruction(Instruction.opc_pop2));
iter.add(new Instruction(Instruction.opc_pop));
break;
}
instr.replaceInstruction(Instruction.opc_pop - 1
+ stacksize);
}
}
}

@ -1,6 +1,7 @@
package jode.obfuscator;
import @COLLECTIONS@.Iterator;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
public class UniqueRenamer implements Renamer {
static int serialnr = 0;

Loading…
Cancel
Save